您的位置:首页 > 其它

对于SOCKET里几个关键点我的理解

2011-08-28 20:36 281 查看
设置非阻塞模式:

int ioctlsocket(

__in SOCKET s,

__in long cmd,

__in_out u_long* argp

);

参数cmd可取值:

FIONBIO:

此时,设置*argp=1,即将s设置为非阻塞,设置*argp=0,s将为非阻塞

要注意的是:The WSAAsyncSelect and WSAEventSelect functions automatically set a socket to nonblocking mode. If WSAAsyncSelect or WSAEventSelect has been issued on a socket, then any attempt to use ioctlsocket to set the socket back to blocking mode will fail with
WSAEINVAL.

To set the socket back to blocking mode, an application must first disable WSAAsyncSelect by calling WSAAsyncSelect with the lEvent parameter equal to zero, or disable WSAEventSelect by calling WSAEventSelect with the lNetworkEvents parameter equal to zero.

FIONREAD:

设置最多能读到多少数据,返回值返回设置后最多能读到的数据量

重点:

1.立刻获得connect的是否成功的结果阻塞模式下connect在75s后会返回是否成功的结果,那如果将这个时间改得短一些呢,比如2s,做法如下:

我们在connect之前将socket设置为非阻塞模式然后调用select,socket是非阻塞的,但select本身却是阻塞的,参数中可以设置时间,示例代码:

int CCameraSocket::Connect( CString ip, UINT port )

{

//先设置为非阻塞,连接成功或失败后再设置为阻塞

unsigned long non_block = 1;

if( ioctlsocket( m_socket, FIONBIO, &non_block ) == SOCKET_ERROR ) return SOCKET_ERROR;

sockaddr_in sock_set;

memset( (char*)&sock_set, 0, sizeof(sock_set) );

sock_set.sin_port = ( port );

sock_set.sin_family = AF_INET;

sock_set.sin_addr.S_un.S_addr = inet_addr( ip.GetBuffer(0)) ; ip.ReleaseBuffer();

if( connect( m_socket, (sockaddr*)&sock_set, sizeof(sock_set) ) == SOCKET_ERROR &&

WSAGetLastError() == WSAEWOULDBLOCK )

{

FD_SET write_set;

FD_ZERO( &write_set );

FD_SET( m_socket, &write_set );

struct timeval time_delay = {2,0};

if ( select( 0, NULL, &write_set, NULL, &time_delay ) == SOCKET_ERROR )

{

return SOCKET_ERROR;

}

else

{

if( FD_ISSET(m_socket, &write_set) )//connect成功,

{

//还原阻塞模式

non_block = 0;

if( ioctlsocket( m_socket, FIONBIO, &non_block ) == SOCKET_ERROR ) return SOCKET_ERROR;

return 0;

}

else return SOCKET_ERROR;

}

}

else

{

return SOCKET_ERROR;

}

return 0;

}

如果你使用MFC中的CAsyncsoket,调用connect后,如果连接成功onConnect会被调用,对于失败的处理,可以设置一个定时器,如果调用成功,就把定时器关掉,

如果定时器成功执行就认为连接失败了,然后做相应处理,

2.非阻塞模式Send时得到WSAWOULDBLOCK错误的处理。收到这个错误意思是缓冲区已满,你的数据没有发送成功,如果你使用了WSAAyncSelect,在缓冲区有空当时FD_ISSET查询FD_WRITE会成功,如果你使用MFC的CAsyncSocket类,在缓冲区有空当时会调用onSend,你要做的就是将发送失败的数据保存起来,在收到

缓冲区有空当的消息时将这些数据重新发出去,

3.粘包问题由于网络问题或者系统底层处理的问题,可能会出现的问题是你想发一个1000K的包的数据出去,结果只发出去900K,就是被分段了,你收数据时就可能先来了个900K,后又来了个100K的,于是你需要把收到的900k的数据和100K的数据重新合并成一个包,具体做法是当收到有数据到来的通知时,调用recv函数收取数据,如果数据小于一个完整包的大小,就将这些数据保存取来之后再收到通知,再次接收数据,和之前的数据拼接在一起,如果拼接后的数据大于一个完整包的大小,那么把这个包处理掉

多余的数据保存,和下去的数据全并处理,以此类推。

4.shutdown和closesocket

TCP是双工的,shutdown可以单方向关闭,如关闭读或者关闭写

或者全部关闭,而closesocket则是立即关闭。关闭时不关心socket缓冲区数据的话,直接closesocket就行了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: