关于网络协议封装的一些新想法

最近业余时间在写一个小游戏。在为客户端封装socket层时头脑一热,有了一些新的想法, 在这里记录一下。 客户端使用的是Unity3d引擎。而在Unity3d中,基础的socket库只提供两种模式,一种是阻塞模式,一种是异步callback模式。 一般都需要基于这两种模式下进一步封装,才可以更方便的使用。 咨询了几个做客户端的并搜了一下,发现大家的惯用手法都是开一个线程去使用socket阻塞去读,然后把读到的数据通过队列传回主线程进行处理。 但是也许是单线程的思维模式已经深入我心了,所以我……

使用缓存优化数据请求

继上一篇场景之后,事情还没有完。 我有一堆struct obj对象(数量级可能为千级), 客户端需要频繁拉取这些信息中的一部分去显示(比如,当切换标签页时)。 由于这一操作可能会很频繁,而struct obj对象并不算小,如果每一次都重新拉取全部数据,有点让人不舒服,而且对流量也是一种很大的浪费。因此就琢磨着怎么去优化整个过程,以使在此过程中使数据传输量最小。 第一反应,肯定就是对整个列表加一个version字段,每当有obj对象改变时,version加1,当客户端进行拉取时,拿着他本地……

listen函数中的backlog字段

今天在公司无意间又拿redis-benchmark测了一下silly的IO并发性并与redis本身比较了一下。 发现在2000个client同时并发的情况下,性能只是Redis的30%的左右。 直觉上这很不正常,虽然silly所有的数据经过lua层时都需要malloc和memcpy,但最多性能上差个10%~20%就已经很可观了,绝对不可能差70%这么多。 通过不断的调整client的个数,我发现性能并没有明显随着client的数量降低而降低,而是在client个数到达某个值时突然降低的。 比如我自己测的数据是在491个client时,silly的性能与r……

tcp使用的进一步了解

以前对socket的了解仅仅局限于listen/connect/epoll/select/close等这些API的表面使用。其具体语义以及一些状态都没有深究。总觉得这样写代码会出问题,今天咬咬牙把《tcp协议卷1》中的Tcp部分又看了一遍。发现由于对协议和API语义的了解不足,在程序中还是犯了不少错误。 TIME_WAIT状态是tcp网络编程中最不容易理解的地方。主动关闭的一方会经历TIME_WAIT状态, 这个状态会经历2MSL的时间。其目的就是为了可靠的实现TCP全双工连接的终止和允许老的重复分组消逝在网络中(具体可以参……

SIGPIPE信号

昨天夜里实现了按行来切为数据包的协议, 今天就迫不及待使用resdis-benchmark来测试一下silly的性能。 结果发现到100000个请求左右时就有一定机率程序会默默的退出, 使用gdb看了一下, 是因为向socket写入数据时触发了SIGPIPE信号。 google了一下发现,当向一个已经关闭的socket第二次写入数据时,就会触发SIGPIPE。 但是我把所有的_socket_close都加了打印也没有发现问题。 最后偶然间发现,如果一个socket被对方关闭, 那么第一次write函数不一定返回出错, 但是第二次write却一……

silly中socket犯的错误

silly的socket模块最初是使用epoll实现的, 后来为了在mac上开发就加入了kevent, 然后使用socket_poll.h来封装成了socket_poll。 但是由于对epoll和kevent的不了解,导致了在实现silly_socket.c文件中的_process函数时犯了一些很silly的错误。 直到昨天去实现异步发送时才突然发现epoll和kevent的不同之处。 linux下,在调用epoll_wait函数时将一个struct epoll_event结构体的数组作为参数传入,当epoll_wait函数返回且返回值大于0时, 则会将当前已经发生的事件和发生事件的文件描……

关于silly

自从写了第一个假server之后, 我就一直在想真正的处理高并发的server是如何做的。然后我就研究了skynet, nginx, Node.js这些服务器程序框架。 这些框架除了skynet, 另外两个框架则仅仅是从使用上进行了了解, 并没有去通读他们的源码。所以基本了解下来,skynet是一个基本actor模式,Node.js则为纯异步模式, nignx则使用了master-worker模式。 纸上得来终觉浅,绝知此事要躬行。 我觉得只是单纯的研究是不够的,还是要自己去实现一下,才会遇到并解决问题,这样才能领会到巨人的思……

tcp的close和shutdown

今天看到”Unix网络编程”第六章中半关闭连接, 对close和shutdown的功能区别产生了疑惑. 代码运行情况如下: 情况1:C(client)与S(server)建立链接之后, 当C向S发送数据之后调用shutdown来关闭写操作(断开链接的四次挥手中的前两次)告诉S, C端已发送数据完成, 此时S依然可向C发送数据. 情况2:C(client)与S(server)建议链接之后, 当C向S发送数据之后调用close来关闭socket(同样发送断开链接的四次挥手的前两次, 后两次挥手将由S端调用close来完成), 此时S端被其他条件阻赛并……

tcp的端口号

虽然写了一年多的网络编程, 但是总觉得有种浮沙筑高台的感觉,于是去买了本unix网络编程卷一去读. 果不其然看到第五章使用netstat去调试第一个程序时就产生了一个疑惑. 这个例子每accept一个连接就去fork一个进程去处理, 当我开了一个server和2个client时发现, server一共会有三个进程存在, 一个是listen, 另外两个是accpet出来的, 但是使用netstat去调试时却发现这三个进程其实共享server进程的bind的端口,以前只是知道”端口是用来标识同一个IP的不同进程之间数据收发”,……