Windows网络编程总结(一)
1. 关于bind
INADDR_ANY 的具体含义是,绑定到0.0.0.0。此时,对所有的地址都将是有效的,如果系统考虑冗余,采用多个网卡的话,那么使用此种bind,将在所有网卡上进行绑定。在这种情况下,你可以收到发送到所有有效地址上数据包。
例如:
SOCKADDR_IN Local;
Local.sin_addr.s_addr = htonl(INADDR_ANY);
另外一种方式如下:
SOCKADDR_IN Local;
hostent* thisHost = gethostbyname("");
char* ip = inet_ntoa(*(struct in_addr *)*thisHost->h_addr_list);
Local.sin_addr.s_addr = inet_addr(ip);
在这种方式下,将在系统中当前第一个可用地址上进行绑定。在多网卡的环境下,可能会出问题。
最常见的方式:
const char LocalIP[] = "192.168.0.100";
SOCKADDR_IN Local;
Local.sin_addr.s_addr = inet_addr(LocalIP);
bind(socket, (LPSOCKADDR)&Local, sizeof(SOCKADDR_IN)
bind的安全问题:
如果你在bind时,使用了INADDR_ANY那么,你将可以在所有有效的地址上进行监听,但是Socket有一个特性:可在同一端口上绑定多个Socket。
让我们看看下面的情况:假设你的系统只有一个IP:192.168.0.100,你希望bind到4096端口。对于下面的两种bind,当数据包到达时,谁会接收到呢?
Local.sin_addr.s_addr = htonl(INADDR_ANY);
Local.sin_addr.s_addr = inet_addr(“192.168.0.100”);
WinSocke库是这样处理的:谁绑定的最明确,谁获取数据包。显然,第二种bind将获取到达的数据包。如果避免这种情况呢?使用SO_EXECLUSINEADDRUSE选项。需要注意的是,此选项在Windows NT 4 Service Pack 4以后(包括SP4)才可以使用。
示例代码:
#ifndef SO_EXECLUSINEADDRUSE
#define SO_EXECLUSINEADDRUSE ((int)(~SO_REUSEADDR))
#endif
SOCKADDR_IN Local;
BOOL val = TRUE;
Local. sin_family = AF_INET;
Local. sin_port = htons(4096);
Local.sin_addr.s_addr = htonl(INADDR_ANY);
setsocketopt(socket,
SOL_SOCKET,
SO_EXECLUSINEADDRUSE,
(char*)&val,
sizeof(val));
bind(socket, (LPSOCKADDR)&Local, sizeof(SOCKADDR_IN)
2.关于connect
在阻塞模式下,当无法建立连接时connect的阻塞时间为20秒左右,可采用gethostbyaddr事先判断到服务主机的路径是否是通的,或者先ping一下对方主机的IP地址。
A、 采用gethostbyaddr阻塞时间不管成功与否为4秒左右。
hostent* remoteHost;
unsigned int addr;
addr = inet_addr("192.168.0.100");
remoteHost = gethostbyaddr((char *)&addr, 4, AF_INET);
if ( NULL != remoteHost )
{
// Remote Host Online
}
B、 采用PING方式时间约2秒左右
3.Nagle算法(TCP_NODELAY选项)
WinSock在默认情况下启用该算法。Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据包的数目。但对于某些应用来说,这种算法将降低系统性能。可使用TCP_NODELAY选项来将此算法关闭。不过,最好先测试关闭Nagle算法确实可以提高发送速度,再设置TCP_NODELAY选项,因为设置后对网络性能有明显的负面影响。另外需要注意,TCP_NODELAY是位于IPPROTO_TCP层的选项。
Nagle算法的不足之处主要有2点:
(1) 在限制数据报头部信息消耗的带宽总量的同时,是以牺牲网络延迟为代价的。
(2) 在发送方的缓冲区中,应用程序发送的数据包发生了粘滞的现象,即发送的若干数据包到接收方接收时变成一包,分不出各个包的界线。
前者因为数据被排队而不是立即发送的,因此不适用于需要快速响应时间的系统。后者则会影响到接收方的数据处理的准确性。
禁用Nagle算法:
int bNodelay = 1;
setsockopt( socket,
IPPROTO_TCP,
TCP_NODELAY,
(char *)&bNodelay,
sizoeof(bNodelay));
4.TCPSegMentSize
TCPSegMentSize是发送接受时单个数据报的最大长度,系统默认为1460Bytes。
在SOCK_STREAM方式下,如果单次发送数据超过1460,系统将分成多个数据报传送,在对方接受到的将是一个数据流,应用程序需要增加断帧的判断。当然可以采用修改注册表的方式改变1460的大小,但MicrcoSoft认为1460是最佳效率的参数,不建议修改。
在工控系统中,建议关闭Nagle算法,每次发送数据小于1460(推荐1400),这样每次发送的是一个完整的数据报,减少对方对数据流的断帧处理。
5.SO_LINGER选项
SO_LINGER 延迟关闭连接,通过struct linger结构来进行控制。
struct linger {
int l_onoff<;
int l_linger;
}
l_linger 需要的超时值(以秒为单位)
l_onoff 为零时表示禁止SO_LINGER(此时,等同于SO_DONTLINGER)
为非零值时表示允许SO_LINGER。
示例:
// 禁止延迟关闭 (SO_DONTLINGER)
struct linger li = {0, 0};
setsockopt(Socket, SOL_SOCKET, SO_LINGER, (char *)&li, sizeof(linger));
6.关于shutdown
int shutdown(
SOCKET s,
int how
);
shutdown函数用于在任何类型的套接字上禁止接收、禁止发送或禁止收发。
how参数有三种:
SD_SEND
此时在该套接字上的后续的发送操作将被禁止。
SD_RECEIVE
此时在该套接字上的后续的接收操作将被禁止。
SD_BOTH
此时在该套接字上的后续的发送/接收操作都将被禁止。
注意事项:
shutdown函数并不关闭套接字,且套接字所占有的资源将被一直保持到closesocket()调用。
无论SO_LINGER设置与否,shutdown函数都不会阻塞。
转自:http://blog.csdn.net/kendiv/article/details/157462