免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4329 | 回复: 7
打印 上一主题 下一主题

HTML5应用越来越多了,应朋友要求写了一个小应用框架 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-03 11:11 |只看该作者 |倒序浏览
  1. /*
  2. * SendBuf.h
  3. *
  4. *  Created on: 2010-8-2
  5. *      Author: zliming
  6. */

  7. #ifndef SENDBUF_H_
  8. #define SENDBUF_H_

  9. #include <vector>

  10. using namespace std;

  11. /*
  12. * tr1/shared_ptr.h在mingw下怪怪,又不想用boost,头太大
  13. */

  14. class SharedBuf {
  15. public:
  16.     SharedBuf(const char* data);
  17.     SharedBuf(const SharedBuf& o);
  18.     ~SharedBuf();
  19.     void        operator=(const SharedBuf& o);
  20.     size_t      Size();
  21.     const char* GetBuffer();

  22. private:
  23.     void ReleaseRef();
  24. private:
  25.     struct Data {
  26.         char*   data;
  27.         int     refCount;
  28.         size_t  len;
  29.     } *ptr;
  30. };

  31. #endif /* SENDBUF_H_ */
复制代码
  1. /*
  2. * SendBuf.cpp
  3. *
  4. *  Created on: 2010-8-2
  5. *      Author: zliming
  6. */

  7. #include "SendBuf.h"
  8. #include <string.h>

  9. SharedBuf::SharedBuf(const char* buf) {
  10.     size_t len = strlen(buf);
  11.     ptr = new Data;
  12.     ptr->len = len + 2;
  13.     ptr->data = new char[ptr->len];
  14.     ptr->data[0] = 0;
  15.     memcpy(ptr->data + 1, buf, len);
  16.     ptr->data[len + 1] = 0xff;
  17.     ptr->refCount = 1;
  18. }
  19. SharedBuf::SharedBuf(const SharedBuf& o): ptr(0){
  20.     operator=(o);
  21. }
  22. SharedBuf::~SharedBuf(){
  23.     ReleaseRef();
  24. }
  25. size_t SharedBuf::Size(){
  26.     if(ptr){
  27.         return ptr->len;
  28.     }
  29.     return 0;
  30. }
  31. const char* SharedBuf::GetBuffer(){
  32.     if(ptr){
  33.         return ptr->data;
  34.     }
  35.     return NULL;
  36. }
  37. void SharedBuf::operator =(const SharedBuf& o){
  38.     //去掉原引用的内存
  39.     ReleaseRef();
  40.     ptr = o.ptr;
  41.     ptr->refCount ++;
  42. }
  43. void SharedBuf::ReleaseRef(){
  44.     if(ptr && --ptr->refCount <= 0){
  45.         delete[] ptr->data;
  46.         delete ptr;
  47.         ptr = 0;
  48.     }
  49. }

复制代码
  1. #ifndef __CLIENT_H__
  2. #define __CLIENT_H__

  3. #include <libZLM/LibZLM.h>

  4. struct SafeDelete
  5. {
  6.     template <typename T>
  7.     void operator ()(T& t)
  8.     {
  9.         if(t)
  10.         {
  11.             delete t;
  12.             t = NULL;
  13.         }
  14.     }
  15. };
  16. #define SAFE_DELETE SafeDelete()

  17. class Client
  18. {
  19. public:
  20.     virtual void Start() { }
  21.     virtual ~Client() { }
  22.     Socket& GetSocket(){ return _socket; }

  23. private:
  24.     Socket  _socket;
  25. };

  26. template<typename C>
  27. class Server
  28. {
  29. public:
  30.     Server(int port) : _listen("0.0.0.0", port) { }
  31.     virtual void Accept(const Error& ec, C* client)
  32.     {
  33.         if(client)
  34.         {
  35.             if(!ec)
  36.                 client->Start();
  37.             else
  38.                 delete client;
  39.         }
  40.         client = new C;
  41.         _listen.AsyncAccept(&client->GetSocket(), Bind(&Server::Accept, this, _1, client));
  42.     }
  43.     virtual ~Server(){}
  44. protected:
  45.     Listen  _listen;
  46. };

  47. #endif//__CLIENT_H__
复制代码
  1. /*
  2. * websocket.h
  3. *
  4. *  Created on: 2010-7-29
  5. *      Author: zliming
  6. */

  7. #ifndef WEBSOCKET_H_
  8. #define WEBSOCKET_H_

  9. #include "Socket.h"

  10. class WebSocket : public Client {
  11. public:
  12.     void            Start();
  13.     virtual void    DoCommand(Record& record);

  14. private:
  15.     void            Do(const Error& err, int len);
  16.     void            OnRead(const Error& err, int len);

  17. private:
  18.     char            buf[0x8000];
  19.     size_t          read_bytes;
  20.     int             step;
  21.     char*           buf_offset;
  22. };

  23. #endif /* WEBSOCKET_H_ */
复制代码
  1. //============================================================================
  2. // Name        : websocket.cpp
  3. // Author      : zliming
  4. //============================================================================

  5. #include "websocket.h"
  6. #include "Handshaker.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <memory.h>
  10. #include <stdio.h>
  11. #include <string>
  12. using namespace std;

  13. static char flash_policy_req[] = "<policy-file-request/>";
  14. static char flash_policy_ret[] = "<cross-domain-policy>\n"
  15.     "<allow-access-from domain='*' to-ports='*'/>\n"
  16.     "</cross-domain-policy>";
  17. static char http_end_flag[] = "\r\n\r\n";

  18. void WebSocket::Start() {
  19.     step = 1;
  20.     read_bytes = 0;
  21.     Do(Error(), 0);
  22. }

  23. void WebSocket::Do(const Error& err, int len) {
  24.     switch (step) {
  25.     case 1:
  26.         step = 2;
  27.         return GetSocket().AsyncRead(buf, sizeof(flash_policy_req), Bind(
  28.                 &WebSocket::Do, this, _1, _2));
  29.     case 2:
  30.         //如果是通过Flash桥来连接的,会先读求连接策略
  31.         if (memcmp(flash_policy_req, buf, sizeof(flash_policy_req)) == 0) {
  32.             step = 3;
  33.             return GetSocket().AsyncWrite(flash_policy_ret,
  34.                     sizeof(flash_policy_ret),
  35.                     Bind(&WebSocket::Do, this, _1, _2));
  36.             case 3:
  37.             return delete this;
  38.         } else {
  39.             case 4:
  40.             read_bytes += len;
  41.             buf[read_bytes] = 0;
  42.             buf_offset = strstr(buf, http_end_flag);
  43.             if (buf_offset) {
  44.                 //HTTP头读完,还要读8个字节(key3)
  45.                 if (buf + read_bytes - (buf_offset + 4) < 8) {
  46.                     step = 5;
  47.                     return GetSocket().AsyncRead(buf + read_bytes, 8 - (buf
  48.                             + read_bytes - (buf_offset + 4)), Bind(
  49.                             &WebSocket::Do, this, _1, _2));
  50.                     case 5:
  51.                     read_bytes += len;
  52.                     buf[read_bytes] = 0;
  53.                 }
  54.                 //全体需要的数据完成
  55.                 Handshaker handshaker(buf, read_bytes);
  56.                 const string& result = handshaker.GetResult();
  57.                 if(result.empty()){
  58.                     return delete this;
  59.                 }
  60.                 memcpy(buf, result.c_str(), result.length());
  61.                 memcpy(buf + result.length(), handshaker.GetChallenge(), 16);

  62.                 read_bytes = 0;
  63.                 return GetSocket().AsyncWrite(buf, result.length() + 16,
  64.                         Bind(&WebSocket::OnRead, this, _1, 0));
  65.             } else {
  66.                 step = 4;
  67.                 return GetSocket().AsyncReadSome(buf + read_bytes, sizeof(buf)
  68.                         - read_bytes - 1, Bind(&WebSocket::Do, this, _1, _2));
  69.             }
  70.         }
  71.     }
  72. }
  73. void WebSocket::OnRead(const Error& err, int len){
  74.     if(!err){
  75.         read_bytes += len;
  76.         char* find, *prog = buf;
  77.         while((find = (char*)memchr(prog, 0xff, buf + read_bytes - prog)) != NULL){
  78.             //websocket发送的数据为: 00 data ff
  79.             *find = 0;
  80.             //这个是Json数据的操作类,和javascript通讯,json是不二选择
  81.             Record record;
  82.             if(record.FromString(prog + 1, find - prog - 1)){
  83.                 this->DoCommand(record);
  84.             }
  85.             //处理完成,跳过已经处理部分数据
  86.             prog = find + 1;
  87.         }
  88.         if(prog != buf){
  89.             //已经处理完的数据丢弃
  90.             memmove(buf, prog, buf + read_bytes - prog);
  91.             read_bytes = buf + read_bytes - prog;
  92.         }
  93.         if(sizeof(buf) - read_bytes - 1 > 0){
  94.             //读新的数据进来
  95.             return GetSocket().AsyncReadSome(buf + read_bytes,
  96.                     sizeof(buf) - read_bytes - 1,
  97.                     Bind(&WebSocket::OnRead, this, _1, _2));
  98.         }
  99.     }
  100.     delete this;
  101. }
  102. void WebSocket::DoCommand(Record& record){

  103. }

复制代码

论坛徽章:
0
2 [报告]
发表于 2010-08-03 11:12 |只看该作者
  1. /*
  2. * Handshaker.h
  3. *
  4. *  Created on: 2010-7-29
  5. *      Author: zliming
  6. */

  7. #ifndef HANDSHAKER_H_
  8. #define HANDSHAKER_H_

  9. #include <string>
  10. using namespace std;

  11. class Handshaker{
  12. public:
  13.     const string&   GetResult();
  14.     const char*     GetChallenge();
  15.     Handshaker(char* req, size_t req_len);

  16. private:
  17.     string          GetValue(const char* key);
  18.     unsigned        GetNumber(const char* value);
  19. private:
  20.     string          result;
  21.     char*           req;
  22.     unsigned char   challenge[16];
  23. };

  24. #endif /* HANDSHAKER_H_ */
复制代码
  1. /*
  2. * Handshaker.cpp
  3. *
  4. *  Created on: 2010-7-29
  5. *      Author: zliming
  6. */

  7. #include "Handshaker.h"
  8. #include "md5.h"
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <algorithm>

  12. unsigned BigEndian(unsigned i){
  13.     return (i << 24) | (i >> 24) |
  14.             ((i & 0xff00) << 8) | ((i & 0xff0000) >> 8);
  15. }

  16. Handshaker::Handshaker(char* req, size_t req_len){
  17.     this->req = req;
  18.     //必须是GET请求
  19.     if(memcmp(req, "GET", strlen("GET")) != 0  ||
  20.             GetValue("Upgrade:") != "websocket" ||
  21.             GetValue("Connection:")!= "upgrade"){
  22.         return;
  23.     }
  24.     string origin = GetValue("Origin:");
  25.     string key1 = GetValue("Sec-WebSocket-Key1:");
  26.     string key2 = GetValue("Sec-WebSocket-Key2:");
  27.     if(origin.empty() || key1.empty() || key2.empty()){
  28.         return;
  29.     }
  30.     char* key3 = req + req_len - 8;
  31.     string uri(req + 4, strchr(req + 4, ' ') - (req + 4));
  32.     string location = "ws://" + GetValue("Host:") + uri;
  33.     unsigned n1 = GetNumber(key1.c_str());
  34.     unsigned n2 = GetNumber(key2.c_str());
  35.     unsigned sc1 = count(key1.begin(), key1.end(), ' ');
  36.     unsigned sc2 = count(key2.begin(), key2.end(), ' ');
  37.     if(sc1 == 0 || sc2 == 0 || n1 % sc1 != 0 || n2 % sc2 != 0){
  38.         return;
  39.     }
  40.     unsigned part1 = BigEndian(n1 / sc1);
  41.     unsigned part2 = BigEndian(n2 / sc2);
  42.     memcpy(challenge, &part1, sizeof(unsigned));
  43.     memcpy(challenge + sizeof(unsigned), &part2, sizeof(unsigned));
  44.     memcpy(challenge + sizeof(unsigned) * 2, key3, 8);
  45.     MD5_CTX ctx;
  46.     MD5_Init(&ctx);
  47.     MD5_Update(&ctx, challenge, sizeof(challenge));
  48.     MD5_Final(challenge, &ctx);

  49.     //返回
  50.     result ="HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
  51.             "Upgrade: WebSocket\r\n"
  52.             "Connection: Upgrade\r\n"
  53.             "Sec-WebSocket-Location: " + location + "\r\n"
  54.             "Sec-WebSocket-Origin: " + origin + "\r\n";

  55.     string proto = GetValue("Sec-WebSocket-Protocol:");
  56.     if(!proto.empty()){
  57.         result += "Sec-WebSocket-Protocol: " + proto + "\r\n";
  58.     }
  59.     result += "\r\n";
  60. }

  61. const char* Handshaker::GetChallenge(){
  62.     return (const char*)challenge;
  63. }

  64. const string& Handshaker::GetResult(){
  65.     return result;
  66. }

  67. unsigned Handshaker::GetNumber(const char* value){
  68.     unsigned ret = 0;
  69.     while(*value){
  70.         if(*value >= '0' && *value <= '9'){
  71.             ret = ret * 10 + *value - '0';
  72.         }
  73.         value++;
  74.     }
  75.     return ret;
  76. }

  77. string Handshaker::GetValue(const char* key){
  78.     string ret;
  79.     char* find = strstr(req, key);
  80.     if(find){
  81.         size_t len = strlen(key);
  82.         find += len + 1;
  83.         ret.append(find, strchr(find, '\r') - find);
  84.         transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
  85.     }
  86.     return ret;
  87. }
复制代码
  1. /*
  2. * Chat.h
  3. *
  4. *  Created on: 2010-8-1
  5. *      Author: zliming
  6. */

  7. #ifndef CHAT_H_
  8. #define CHAT_H_

  9. #include "websocket.h"
  10. #include "SendBuf.h"
  11. #include <string>

  12. class Chat : public WebSocket {
  13. public:
  14.     void DoCommand(Record& record);
  15.     void SendChat(SharedBuf chat);
  16.     ~Chat();

  17. private:
  18.     void FinishSend(SharedBuf);
  19. private:
  20.     string username;
  21. };

  22. #endif /* CHAT_H_ */
复制代码
  1. /*
  2. * Chat.cpp
  3. *
  4. *  Created on: 2010-8-1
  5. *      Author: zliming
  6. */

  7. #include "Chat.h"
  8. #include <string.h>
  9. #include <map>

  10. //只有一个IORUN,不需要互斥
  11. map<string, Chat*> users;

  12. void Chat::DoCommand(Record& record) {
  13.     if (memcmp("login", (const char*)record["cmd"], sizeof("login")) == 0) {
  14.         Record ret;
  15.         ret["cmd"] = "login";
  16.         if (users.find((const char*) record["value"]) != users.end()) {
  17.             ret["value"] = "user online";
  18.         } else {
  19.             ret["value"] = "ok";
  20.             username = (const char*) record["value"];
  21.             users[username] = this;
  22.         }
  23.         SharedBuf buf(ret.ToString());
  24.         SendChat(buf);
  25.     } else if (!username.empty() &&
  26.             memcmp("chat", (const char*)record["cmd"], sizeof("chat")) == 0) {
  27.         //用户在线,发聊天包时加上用户名
  28.         record["user"] = username.c_str();
  29.         SharedBuf buf(record.ToString());
  30.         for (map<string, Chat*>::iterator it = users.begin(); it != users.end(); ++it) {
  31.             it->second->SendChat(buf);
  32.         }
  33.     }
  34. }
  35. void Chat::SendChat(SharedBuf chat) {
  36.     //在发送完成处理中引用这个SharedBuf,不让它过早释放
  37.     GetSocket().AsyncWrite((char*)chat.GetBuffer(), chat.Size(),
  38.             Bind(&Chat::FinishSend, this, chat));
  39. }
  40. void Chat::FinishSend(SharedBuf){

  41. }
  42. Chat::~Chat() {
  43.     if(!username.empty()){
  44.         users.erase(username);
  45.         //通知用户下线
  46.         Record ret;
  47.         ret["cmd"] = "logout";
  48.         ret["value"] = username.c_str();
  49.         SharedBuf buf(ret.ToString());
  50.         for (map<string, Chat*>::iterator it = users.begin(); it != users.end(); ++it) {
  51.             it->second->SendChat(buf);
  52.         }
  53.     }
  54. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2010-08-03 11:19 |只看该作者

论坛徽章:
0
4 [报告]
发表于 2010-08-03 11:46 |只看该作者
回复 1# zliming


    什么应用的?能否给个说明

论坛徽章:
0
5 [报告]
发表于 2010-08-03 12:00 |只看该作者
能否给个说明
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

论坛徽章:
0
6 [报告]
发表于 2010-08-03 13:11 |只看该作者
html5的websocket,使js可以用tcp长连接通信的一个东西

这里用这个做一个聊天演示

论坛徽章:
1
CU十二周年纪念徽章
日期:2013-10-24 15:41:34
7 [报告]
发表于 2010-08-03 13:15 |只看该作者
那还得要用支持html5的浏览器吗?

论坛徽章:
0
8 [报告]
发表于 2010-08-03 13:22 |只看该作者
嗯,现在html5浏览器才刚起步,不过这个东西在不支持html5的浏览器中调用flash模拟websocket连接
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP