过年也有没事做耍电脑的时候,就用C在windows上写了个websocket客户端的五子棋,这个是用opengl画的,棋盘是3D的但做得简陋,用socket实现的websocket协议与以前写的websocket server通信,可以与以前实现的HTML5五子棋游戏对玩。
前面挂了个“电视机”,房间没人进入的时候是没有信号的状态,有人进入后会显示钓鱼脸先生。
过年也有没事做耍电脑的时候,就用C在windows上写了个websocket客户端的五子棋,这个是用opengl画的,棋盘是3D的但做得简陋,用socket实现的websocket协议与以前写的websocket server通信,可以与以前实现的HTML5五子棋游戏对玩。
前面挂了个“电视机”,房间没人进入的时候是没有信号的状态,有人进入后会显示钓鱼脸先生。
在以前实现的websocket服务器基础之上又加了一个五子棋对战游戏.现在服务器已经支持火拼俄罗斯方块和五子棋两个网络对玩的游戏了.
这个游戏同样支持电脑和手机的HTML5浏览器,由于这一次的游戏界面是自伸缩,所以对不同浏览器的效果都还不错.
由于手机屏幕比较小和手指难准确定位的因素,所以特地给触屏事件添加了放大处理,当第一次点击棋盘时,放大棋盘,第二次点击要放置的位置时才放置棋子.放大模式下,两个手指点击棋盘时缩小到全盘大小. 电脑上则不进行这样的逻辑处理,直接点击棋子放置区域放置棋子.
有vps就是好! 抽了几个周末的空闲时间完成了火拼俄罗斯的websocket服务器及客户程序,现在已经支持新版的websocket协议和苹果设备支持的websocket协议. 做这个的初衷是为了几个人在一起无聊的时候可以用手机连机玩些小游戏打发无聊时光.本人已经测试即使走最慢的移动的Edge网络,也不影响相互连机.
火拼俄罗期电脑的玩法跟QQ游戏的一样,上下左右方向键控制移动和旋转,空格直接下落,数字1,2,3,4使用道具给指定号码的玩家.
手机是通过在屏幕任意位置滑动时左右移动,点击自己游戏区域的上部变形,点击自己游戏区域的下部分下落,点击玩家编号向指定玩家使用道具.
游戏大厅地址: http://www.hoverlees.com/game
经过本人对WebSocket协议的研究和WebSocket服务器的编写,对WebSocket有了深入的了解,在此写个总结供以后研究参考。
本文地址:http://www.hoverlees.com/blog/?p=1413
1.概要
WebSocket是最新提出用于实现服务器与浏览器双向通信的一种解决方案,用于取代一些传统的数据推送方案(如iframe长连接,ajax轮询等)。该方案由于一直在草案阶段,最新的版本为version 13.该版本出现在RFC6455中。而在safari(包括桌面和移动版本)上则是使用的websocket的 draft-ietf-hybi版。照这个趋势看来,WebSocket早晚会向RFC6455的方向定型。
在本文中,称RFC6455版的chrome版,safari使用的版本为safari版。
最近在写WebSocket的服务器,打算同时做基于websocket的游戏及游戏服务器。研究了一下WebSocket协议,然后基于epoll写了一个websocket的服务器,可支持超大并发量^_^,这儿向大家提供数据包解析和创建的函数,供大家学习参考。
功能参考RFC 6455 ,目前最新的websocket v13版本的协议写成。支持mask和非mask两种方式,支持解析和创建数据长度在6K以下的WebSocket数据包。
这儿只是个解析示例,现实的网络开发中应使用流解析方式生成,流方式的实现即通过向一个状态机添加缓冲区,当状态机组合出一个包头时回调。
本文地址: http://www.hoverlees.com/blog/?p=1395
//websocket.h /** * WebSocket数据包解析和生成函数,RFC 6455 WebSocket V13 标准 * @author Hoverlees http://www.hoverlees.com */ #ifndef __HOVERLEES_WEBSOCKET_H #define __HOVERLEES_WEBSOCKET_H #define OPCODE_CONTINUATION 0 #define OPCODE_TEXT 1 #define OPCODE_BINARY 2 #define OPCODE_CLOSE 8 #define OPCODE_PING 9 #define OPCODE_PONG 10 typedef struct WebSocketPacket{ unsigned char fin; unsigned char mask; unsigned char opcode; unsigned char mask_key[4]; int data_len; unsigned char* data; }WebSocketPacket; int websocket_packet_parse(unsigned char* mem,int len,WebSocketPacket* packet,int data_len); int websocket_packet_build(unsigned char* data,int len,WebSocketPacket* packet); #endif //websocket.c /** * 解析WebSocket数据包 ,参考RFC 6455 page27 * http://tools.ietf.org/html/rfc6455#page-27 * @param mem 数据包内存 * @param len 数据包长度 * @param packet 解析后的数据将存到这个对象中,请在传入packet之前初始化packet的data指针指向一块可用内存. * @param data_len packet的内存块可接收的最大字节数 * @return 如果解析成功返回1,解析失败返回0 */ int websocket_packet_parse(unsigned char* mem,int len,WebSocketPacket* packet,int data_len){ int i,j; int pos; pos=2; i=mem[1]&127; if(i==127){ //大于65536的数据包不适合用这种解析方式。应该使用流解析方式。 return 0; } else if(i==126){ i=mem[2]*256+mem[3]; pos=4; } if(i>data_len) return i-data_len; packet->fin=(mem[0]&128) ? 1:0; packet->opcode=mem[0]&0xf; packet->mask=mem[1]&128; packet->data_len=i; if(packet->mask){ for(i=0;i<4;i++){ packet->mask_key[i]=mem[pos+i]; } pos+=4; for(i=0;i<packet->data_len;i++){ j=i%4; packet->data[i]=mem[pos+i]^packet->mask_key[j]; } } else{ for(i=0;i<packet->data_len;i++){ packet->data[i]=mem[pos+i]; } } packet->data[i]=0; return 1; } /** * 创建数据包 * @param data 要发送的数据实体 * @param len 数据长度 * @param packet 数据包,生成的数据在数据包的data中,传入前请先初始化data指针以及需要的参数 * @return 最终生成的块大小 */ int websocket_packet_build(unsigned char* data,int len,WebSocketPacket* packet){ int pos=0; int i,j; if(len>65528) return 0; packet->data[0]=packet->fin? 128:0; packet->data[0]|=packet->opcode; if(len>=126){ packet->data[1]=126; packet->data[2]=(len>>8)&0xFF; packet->data[3]=len&0xFF; pos=4; } else{ packet->data[1]=len&0xFF; pos=2; } packet->mask=0; //为了支持稍老一点的浏览器 if(packet->mask){ packet->data[1]|=128; for(i=0;i<4;i++){ packet->data[pos+i]=packet->mask_key[i]; } pos+=4; for(i=0;i<len;i++){ j=i%4; packet->data[pos+i]=data[i]^packet->mask_key[j]; } } else{ for(i=0;i<len;i++){ packet->data[pos+i]=data[i]; } } pos+=len; return pos; }
websocket体验:
基于websocket的火拼俄罗斯