char *ip = "www.baidu.com";
int value = inet_addr(ip);
if( value == INADDR_NONE )
{
hostent *phost = gethostbyname(ip);
int i = 0;
while( phost->h_addr_list[i] != NULL ) //注意:不能直接打印 phost->h_addr_list[i].它存储的是网络字节序
{
in_addr addr;
memcpy( &addr, phost->h_addr_list[i], phost->h_length);
char *p = inet_ntoa( addr );
std::cout << p << std::endl;
std::cout << inet_addr( p ) << " " << addr.S_un.S_addr << std::endl; //直接用addr.S_un.S_addr很方便啊,不用再此转换
i++;
}
}
2.RST状态
1.如果listen的tcp收到一个到达的ACK会回应RST
2.如果tcp在SYN_SENT状态收到的应答序号小于初始序号(ISS)或者大于下一个发送序号,会发送RST
3.如果tcp在SYN_RECV状态收到一个不在接收窗口内的tcp段,会发送RST
4.如果一个tcp连接已主动关闭并在2MSL等待期间或者已完全关闭(CLOSED)收到tcp段,也可能会发送RST
3.“当用户disconnect后,如果对应的socket没有任何操作悬挂循环中,那么你是无法得到通知的,直到某个时候程序想起这个socket并进行一个操作后才会得到知该客户已经断开”
4.WSARecv函数还有另外一个作用,如果客户端断开连接了,WSARecv会收到一个0字节的返回,我们可以根据这个释放连接对象。如果客户端直接拔网线,WSARecv是检测不到,这是我们要根据超时来检测。
转引自网络:
当关闭完成端口时,如果还有未处理的Accepte操作,应该先关闭ListenSocket,然后在IOCP中,处理这些Accept操作(进行资源释放等),切记不要强行终止那些没有处理的Accept操作,否则会造成内存泄漏。
关于closesocket操作:
The closesocket function will initiate cancellation on the outstanding I/O operations, but that does not mean that an application will receive I/O completion for these I/O operations by the time the closesocket function returns. Thus, an application should not cleanup any resources (WSAOVERLAPPED structures, for example) referenced by the outstanding I/O requests until the I/O requests are indeed completed.
在IOCP模式下,如果调用closesocket时有未决的pending IO,将导致socket被重置,所以有时会出现数据丢失。正统的解决方式是使用shutdown函数(指定SD_SEND标志),注意这时可能有未完成的发送pengding IO,所以你应该监测是否该连接的所有是否已完成(也许你要用一个计数器来跟踪这些pending IO),仅在所有send pending IO完成后调用shutdown。
MSDN推荐的优雅关闭socket:
- Call WSAAsyncSelect to register for FD_CLOSE notification.
- Call shutdown with how=SD_SEND.
- When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR.
- Call closesocket.
FD_CLOSE being posted after all data is read from a socket. An application should check for remaining data upon receipt of FD_CLOSE to avoid any possibility of losing data.
对每个使用AcceptEx接受的连接套结字使用setsockopt设置SO_UPDATE_ACCEPT_CONTEXT选项,这个选项原义是把listen套结字一些属性(包括socket内部接受/发送缓存大小等等)拷贝到新建立的套结字,却可以使后续的shutdown调用成功。
/* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work fine*/
setsockopt( sockClient,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char*)&m_sockListen,
sizeof(m_sockListen) ) ;
如果是调用AcceptEX接收的连接 不设置该选项的话,随后的shutdown调用
将返回失败, WSAGetLastError() returns 10057 -- WSANOTCONN
1.使用OVERLAPPED时,一定要memset(&ovl, 0, sizeof(ovl));
2.list::erase(iter);会调用析构函数
3.使用scopelock时,必须用引用,复制无效!
4.WSABuf的内存分配
5.dwCompletionkey不能分配在栈上
6.用AcceptEx时,对端connect时会收到OP_ACCEPT通知,同时dwBytesTransferred为0,lpOverlapped不为0
客户端关闭后服务端是无法收到通知的,必须用心跳包
{
骨头(50635102) 14:45:54
心跳尽量自己发. 不要使用套接字提供的.
(me)14:46:03
为什么?
骨头(50635102) 14:46:33
你懂细节 才能规避陷阱. 如果你什么都不知道. 还是自己发的好.
交谈中请勿轻信汇款、中奖信息、陌生电话,勿使用外挂软件。
骨头(50635102) 14:47:33
你想想他的执行权是谁给的.
葬花淚 分享文件 14:47:49
"需要翻译的.txt" 下载
葬花淚(174189648) 14:47:58
......
发错
顶风作案(158513320) 14:48:07
我也是自己的写
自己写的
骨头(50635102) 14:48:20
弄一个timer就好.
顶风作案(158513320) 14:48:21
不过我是用定时器搞的
但是也存在问题啊
需要处理链接啊
状态检测啥的
自己考虑的东西比较多
骨头(50635102) 14:49:19
不懂你说的是什么.
顶风作案(158513320) 14:49:33
你要看看服务器的状态吧
还得遍历客户端列表把
骨头(50635102) 14:49:46
没有心跳. 这些你也得处理.
顶风作案(158513320) 14:50:06
如果用系统的是不是就不需要了
}
调用AcceptEx后,如果立即接着closesocket, GetXXX会返回TRUE,服务端会收到RECV通知,dwByetsTransferred为0。
,如果间隔一段时间再closesocket,GetXXX会返回FALSE,dwByetsTransferred为0。
1.使用semphore来决定投递AcceptEx要注意的:
开始时WaitXXX来投递,在连接被接收后要ReleaseSemaphore
2.同时,在投递AcceptEx前,先将预准备的socket放在容器当中,在程序出错或结束的时候清空容器,以清理未被接受的socket
3.将SOCKET和BUFFER分开,以便在GetCompletionStatus()时方便处理,这样做还有一个好处是在服务器要主动关闭时
能轮询所有的socket,逐个shutdown。然后逐个等待一段时间,最后closesocket
本地测试,客户端只连接不发送数据,服务端收到连接后如果投递recv,连接为2500左右,如果不投递recv,连接为1.6W左右