part 1.
为什么要使用 chBEGINTHREADEX() 而不直接使用 CreateThread() 来创建线程?
对于用C/C++编写的多线程应用程序,始终都应该使用_beginthreadex() 函数来创建新线程。
具体原因请参阅《Windows 核心编程》。Jeffrey 在书中花了好几页的篇幅来讲述这个重要的问题。
part 2.
命令行参数:
-b n 将n绑定为客户的本地端口号(在默认情况下,系统给客户分配一个临时端口号)。一般来
说我们不应该为UDP套接字指定本机网络接口。对于多网络接口的主机,路由表才真正决
定UDP数据报在那个物理接口上传出去。
g_nBindLocalPort = -1
-i 源客户或接收器服务器。向网络写数据(默认,即作为源客户),或者如果和-s选项一起用,
从网络读数据。-n选项可以指明写(或读)的缓存的数目,-w选项可以指明每次写的大小,
-r选项可以指明每次读的大小。
g_bSource = FALSE
-n n 当和-i选项一起使用时,n指明了读或写的缓存的数目。n的默认值是1024。
g_nNumberOfRW = 1024
-p n 指明每个读或写之间暂停的秒数。这个选项可以和源客户(-i)或接收服务器(-is)一起使用
作为每次对网络读写时的延迟。参考-P选项,实现在第1次读或写之前暂停。
g_nPauseOfEveryTime = -1
-q n 为TCP服务器指明挂起的连接队列的大小:TCP将为之进行排队的、已经接受的连接的数目
。默认值是5。
g_nBacklog = 5
-r n 和-is一起使用,n指明每次从网络读数据的大小。默认是每次读1024字节。
g_nNumberOfRead = 1024
-s ip port 作为一个服务器,而不是客户。在接口ip的port端口上进行监听。
g_szLocalInterface[128] = {0}
g_nBindLocalPort = -1
g_bServer = TRUE
-u 使用UDP,而不是TCP。默认使用TCP。
g_bUseUDP
-v 详细模式。在标准差错上打印附加的细节信息(如客户和服务器的临时端口号)。
g_bParticular = FALSE
-w n 和-i选项一起使用,n指明每次从网络中写数据的大小。默认值是每次1024字节。
g_nNumberOfWrite = 1024
-A 使用SO_REUSEADDR插口选项。对于TCP,这个选项允许进程给自己分配一个处于2MSL等待
的连接的端口号。对于UDP,这个选项支持多播,它允许多个进程使用同一本地端口来接
收广播或多播的数据报。
g_bReuseAddr = FALSE
-B 使用SO_BROADCAST插口选项,允许向一个广播IP地址发送UDP数据报。
g_bBroadCast = FALSE
-D 使用SO_DEBUG插口选项。这个选项使得内核为这个TCP连接维护另外的调试信息。
g_bSaveDebugInfo = FALSE
-E 如果实现支持,使用SO_RECVDSTADDR插口选项。这个选项用于UDP服务器,用来打印接收
到的UDP数据报的目的IP地址。遗憾的是Windows的IP实现似乎并不支持这个套接字选项。
-F 指明一个并发的TCP服务器。即,服务器使用fork函数为每一个客户连接创建一个新的进
程(这个选项描述摘自Stevens对他的sock程序撰写的附录)。
我取消了这个选项,因为我的sock实现一开始就设计为使用多线程同时为多个客户提供
服务。
-K 使用TCP的SO_KEEPALIVE插口选项(第23章)。
g_bKeepAlive = FALSE
-L n 把一个TCP端点的拖延时间(linger time)(SO_LINGER)设置为n。一个为0的拖延时间意味
着当网络连接关闭时,正在排列等着发送的任何数据都被丢弃,向对方发送一个重置报
文(18.7节)。一个正的拖延时间(秒)是关闭网络连接必须等待的将所有正在排队等着发
送的数据发送完并收到确认的时间。关闭网络连接时,如果这个拖延定时器超时,挂起
的数据没有全部发送完并收到确认,关闭操作将返回一个差错信息。
g_nLingerTime = -1
-N 设置TCP_NODELAY插口选项来禁止Nagle算法(19.4节)。
g_bNoDelay = FALSE
-O n 指明一个TCP服务器在接受第一个客户连接之前暂停的秒数。
g_nTCPSeverPauseOfFirst = -1
-P n 指明在第一次对网络进行读或写之前暂停的秒数。这个选项可以和接收服务器(-is)一起
使用,完成在接受了客户的连接请求之后但在执行从网络中第一次读之前的延迟。和源
客户(-i)一起使用时,完成连接建立之后但第一次向网络写之前的延迟。参看-p选项,
实现在接下来的每一次读或写之间进行暂停。
g_nPauseOfFirstRW = -1
-R n 把插口的接收缓存(SO_RCVBUF插口选项)设置为n。这可以直接影响TCP通告的接收窗口的
大小。对于UDP,这个选项指明了可以接收的最大的UDP数据报。
g_nRcvBuf = -1
-S n 把插口的发送缓存(SO_SNDBUF插口选项)设置为n。对于UDP,这个选项指明了可以发送的
最大的UDP数据报。
g_nSndBuf = -1
-T host port 指定服务器的主机名或IP地址,以及端口号。这是我新增加的选项,为了让实现更简单一
点。
例子:
sock -v sun 6666 使用系统分配的临时TCP端口连接到主机sun的6666端口,并输出细
节信息。
sock -b1092 -u -v bsdi 6666 在UDP的1092端口上连接到目的主机bsdi的6666端口,并输出细节
信息。
sock -s 10.252.1.33 6666 在10.252.1.33的6666端口上开始运行一个TCP服务器进程。
sock -u -v -s 6666 在所有接口的6666端口上开始一个UDP服务器进程。并输出细节信息。
part 3.
关于Stevens的sock程序的详细描述。
sock程序运行在以下四种模式之一:
1) 交互式客户:默认模式。程序和一个服务器相连,然后将标准输入的数据传给服务器,再将
从服务器那里接收到的数据复制到标准输出。如图R-1所示。
标准输入--->|--------| TCP连接 |--------|
| sock |<--------------------->| 服务器 |
标准输出<---|--------| |--------|
图R-1 sock程序作为交互式客户所作的默认操作
我们必须指明服务器主机的名字和想要连接的服务的名字。主机可指明为点分十进制数,服务可
以指明为一个整数的端口号。从sun到bsdi与标准echo服务器(1.12节)相连,回显我们键入的每一
个字符:
sun % sock bsdi echo
a test line 我们键入这一行
a test line echo服务器返回一个复制行
^D 键入文件结束符来中止
2) 交互式服务器:指明-s选项。需要指明服务名字(或端口号):
sun % sock -s 5555 作为一个在端口5555监听的服务器
程序等待一个客户的连接请求,然后将标准输入复制给客户,将从客户接收到的东西复制到标准输
出。在命令行中,端口号之前可以是一个因特网地址,用来指明接收那一个本地接口上的连接:
sun % sock -s 140.252.13.33 5555 只接受来自以太网的连接
默认的模式是接受任何一个本地接口上的连接请求。
3) 源客户:指明-i选项。在默认情况下,将一个1024字节的缓存写到网络中,写1024次。-n选项和
-w选项可以改变默认值。例如,
sun % sock -i -n12 -w4096 bsdi discard
把12个缓存,每个包含4096字节的数据,送给主机bsdi上的discard服务器。
4) 接收服务器:指明-i选项和-s选项。从网络中读数据然后扔掉。
这些例子都使用了TCP(默认情况),-u选项指明使用UDP。
sock程序有许多选项,用于对程序的运行提供更好的控制。我们需要使用这些选项来产生本书中用到
的所有测试条件。
-b n 将n绑定为客户的本地端口号(在默认情况下,系统给客户分配一个临时端口号)。
-c 将从标准输入读入的新行字符转换为一个回车符和一个换行符。类似地,当从网络中读数据时,将<回车,
换行>序列转换为新行字符。很多因特网应用需要NVT ASCII(26.4节),它使用回车和换行来终止每一行。
-f a.b.c.d.p 为一个UDP端点指明远端的IP地址(a.b.c.d)和远端的端口号(p)。
-h 实现TCP的半关闭机制(18.5节)。即,当在标准输入中读到一个文件结束符时并不终止。而是在TCP连接
上发送一个半关闭报文,继续从网络中读取报文直到对方关闭连接。
-i 源客户或接收器服务器。向网络写数据(默认),或者如果和-s选项一起用,从网络读数据。-n选项可以指
明写(或读)的缓存的数目,-w选项可以指明每次写的大小,-r选项可以指明每次读的大小。
-n n 当和-i选项一起使用时,n指明了读或写的缓存的数目。n的默认值是1024。
-p n 指明每个读或写之间暂停的秒数。这个选项可以和源客户(-i)或接收服务器(-is)一起使用作为每次对网
络读写时的延迟。参考-P选项,实现在第1次读或写之前暂停。
-q n 为TCP服务器指明挂起的连接队列的大小:TCP将为之进行排队的、已经接受的连接的数目(图18-23)。默
认值是5。
-r n 和-is一起使用,n指明每次从网络读数据的大小。默认是每次读10