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

设置非阻塞模式:
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就行了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值