1.使用同步SOCKET就用select模型,并且最好带一个超时
2.Assuming 0 is an invalid socket handle value. Uncontrollably lame.
3
the proper closure of a connected stream socket involves:
call shutdown() with the how equal to 1
loop on recv() until it returns 0 or fails with any error
call closesocket()
Call WSACleanup()
4.使用strlen()来获取host ip的长度
5
Assuming that a UDP datagram of any length may be sent. Criminally lame.
Reason: Various networks all have their limitations on maximum transmission unit (MTU). As a result, fragmentation will
occur, and this increases the likelihood of a corrupted datagram (more pieces to lose or corrupt). Also, the TCP/IP service
providers at the receiving end may not be capable of re-assembling a large, fragmented datagram.
Alternative: Check for the maximum datagram size with the SO_MAX_MSG_SIZE socket option, and don’t send anything larger.
Better yet, be even more conservative. A max of 8K is a good rule-of-thumb.
不要发送太长的数据,不然会因MTU分块,8K刚好
6.
Expecting errors when UDP datagrams are dropped by the sender, receiver, or any router along the way. Seeping lameness from
every crack and crevice.
Reason: UDP is unreliable. TCP/IP stacks don’t have to tell you when they throw your datagrams away (a sender or receiver
may do this when they don’t have buffer space available, and a receiver will do it if they cannot reassemble a large
fragmented datagram.
Alternative: Expect to lose datagrams, and deal. Implement reliability in your application protocol, if you need it (or use
TCP, if your application allows it).
**************************************
模型选择
1.尽量避免用select()
2.少量连接用WSAAsyncSelect或WSAEventSelect
3.大量连接用Overlapped IO/Completion Port
Silly Window Syndrome:
发送端send太快,对方接受太慢,以至于接收方一但有N个“滑动窗口可用时”,发送方立马发送N个字节的数据,
这会使Overhead非常大,对应策略是用delayed ACK
Winsock is not required to give you all the data it has queued on a socket even if your recv() call gave Winsock enough
buffer space. It may require several calls to get all the data queued on a socket.
除非需要考虑实时性,否则不要关闭Nagle算法
对于TCP字节流,可用2种处理方法:
1.在发送数据前加2个或多个字节的“长度”
有效使用TCP:
数据结构要处理好(内存对齐问题)
WSAData不用初始化,WSAStartup() fills this structure in for you.
2.在数据之后加“断开标示”,如HTTP的 \r\n
用WINSOCK编写的程序可以和UNIX系统通信
TCP connections with Winsock are designed to work the same way:
1.One side finishes sending data. It tells this to the stack by calling shutdown() with the how parameter set to SD_SEND.
2.Both sides continue to call recv(). The side that closed its sending half of the connection must because the remote peer
probably isn’t done sending yet. The peer that is still sending must continue calling recv() because it will get 0 when the
remote peer calls shutdown() with SD_SEND. If you are using asynchronous sockets or event objects, you will get an FD_CLOSE
when this happens, too. In programs that use select(), you simply get a signaled socket in the readfds, which tells you to
call recv(), whereupon you get the 0 return value. Beware that both sides still have to be prepared to receive a -1 return
from recv(), indicating an error.
3.Both sides call closesocket() only when they are convinced the conversation is over, either because they have stopped
sending and they got 0 from recv(), or they got a connection error.
Not following this graceful shutdown protocol can cause data loss.
Nonblocking or asynchronous sockets complicate this. You can either build “finish sending/receiving” logic into your
normal I/O loop, or you can temporarily put the socket in blocking mode and do the last bits of I/O that way. The proper
choice depends on your program’s architecture and requirements.
Is it possible to close the connection “abnormally”?
The simplest way is to call shutdown() with the how parameter set to SD_BOTH (“both directions”), optionally followed by a
closesocket() call. Another method is to set the SO_LINGER flag to 0 with the setsockopt() call before you call closesocket
(). This causes a TCP connection reset. (That is, a TCP packet goes out with the RST flag set, forcing the remote stack to
drop the connection immediately.)
Notes:
Keep in mind that if an overlapped operation fails immediately (that is, returns SOCKET_ERROR and the error is not WSA_IO_PENDING),
then no completion notification will be posted to the queue. Alternately, if the overlapped call succeeds or fails with WSA_IO_PENDING,
a completion event will always be posted to the completion port.
IO模型选择:
客户端可以用overlapped I/O or WSAEventSelect,如何客户端是一个基于窗口的程序,可以用WSAAsyncSelect
禁用Nagle算法的时机:
"Aside from these problems, disabling the Nagle algorithm almost always causes a program's throughput to degrade. The only time you should disable the algorithm is when some other consideration, such as packet timing, is more important than throughput.
Often, programs that deal with real-time user input will disable the Nagle algorithm to achieve the snappiest possible response, at the expense of network bandwidth. Two examples are X Window servers and multiplayer network games. In these cases, it is more important that there be as little delay between packets as possible than it is to conserve network bandwidth."
使用select时要注意的一个问题:
通常使用select()时,表示可以并发处理连接,但这里有一个问题,如果服务器的socket因为客户端发送
connect而激活了,但在调用accept()之前,客户端又关闭了这个连接,则整个程序可能因此而挂起,
所以将 socket设为non-blocking是很重要的。
使用WaitForMultipleObjects()的问题:
1.该函数返回的是第一个被激发的句柄数组的索引,但没有指示被激发的句柄的数目,也没有一种方法来
扫描被激发的句柄,因此,必须多次调用WaitForMultipleObjects()来查找被激发的句柄,与此相反,select()
uifa返回一组活动的IO句柄,以及句柄的数目。
2.该函数不保证公正的通知分发,即,他总是返回数组最前面的活动句柄,而不管数组中其他活动句柄的等待时间。