菜菜地写下心得...[高手批评,观者参考]
最近一次作业,写一个socket程序,超简单的那种,就C/S架构,客户端发服务器端接,然后服务器把接到的东西在发回给客户端,TCP的,用到的方法无非就是socket()、bind()、listen()、accept()、connect()、send()、recv()、closesocket(),还有那WSAStartup()、WSACleanup()、WSAGetLastError(),老简单了是不是,虽然接触socket时间不长,这种程序还是没什么问题的,勒莫....
int listen(
__in SOCKET s,
__in int backlog
);
TCP的服务器端socket基本流程socket->bind->listen->accept->send/recv->closesocket,客户端基本流程socket->[bind->]->connect->send/recv->closesocket,其中客户端connect函数应该是和服务器端的listen函数相互作用,而不是accept函数。在listen函数中的第二个参数backlog代表着等待处理的连接队列(以下简称队列)的长度,神马意思?我也不太懂,但是通过代码实践,我可以简单的说,每当有一个客户端connect了,listen的队列中就加入一个连接,每当服务器端accept了,就从listen的队列中取出一个连接,转成一个专门用来传输数据的socket(accept函数的返回值),所以在服务器端程序中有两个socket,前者是用来接收客户端连接的socket...到这儿我就不太明白了,这似乎不像插座喔,用插座怎么描述这个过程...
拿经典情形来说,设置backlog值为1,那么能够往队列中塞的连接的数量为1,也就是服务器端能够接受的连接数为1,如果一个服务器端程序只有listen函数没有执行accept,那么会发现只有一个客户端能够进行连接,但由于服务器端没有accept,所以listen的队列中的连接就不能被取出了。但是如果有accept函数就不一样了,在服务器端是单线程情况下,listen一旦得到一个连接,加入队列之后就马上被accept函数取走了,然后又能有一个客户端连上,这就出现了似乎有两个客户端能够同时连接服务器端的情形,如果第一个连接此时一直没能断开,listen队列中的那个唯一的连接就不能取出,队列长度为1,新的客户端就不能connect上服务器端。其后面发生的事情就是这样的了。
另外再加一句,当accept生成的那个专门的用来传输数据的socket没有被close(closesocket函数)掉之前,accept是不会释放那个socket的,也就是说在close之前,accept无法从listen的队列中取出一个新的连接转成传输专用的socket。因此在服务器端单线程情况下,accept只有1个,backlog值为1,1+1 = 2,也就是前段说到的能够有两个客户端能够同时连接服务器端。但是如果服务器端是多线程的,就可以存在多个accept,那么这个backlog值的作用也就不怎么明显了,因为大家都在疯狂地从队列中取出连接,listen队列总是不为满的。
总而言之,connect往listen队列填装连接,每一个accept操作都会从listen队列取连接转成socket,等待这个socket close掉之后再继续从listen队列中取连接,而listen队列长度就是listen函数的第二个参数--backlog。