Winsock 同步方式 编程要点

1 默认用作同步阻塞方式

那就是当你从不 调用 WSAIoctl() ioctlsocket() 来改变 Socket IO 模式.

也从不调用 WSAAsyncSelect() WSAEventSelect() 来选择需要处理的 Socket 事件。


正是由于函数 accept() WSAAccept() connect() WSAConnect() send() WSASend() recv() WSARecv() 等函数被用作阻塞方式.


2 、如果作为异步非阻塞方式用 ,那么程序主 要就是要处理事件。它有两种处理事件的办法: _H`y0nW  
 
第一种,它常关联一个窗口,也就是异步 Socket 的事件将作为消息发往该窗口,这是由 WinSock 扩展规范里的一个函数 WSAAsyncSelect() 来实现和窗口关联。最终你只需要处理窗口消息,来收发数 据。 RejT/dEy  
 
第二种,用到了扩展规范里另一个关于事件的函数 WSAEventSelect() ,它是用事件对象的方式来处理 Socket 事件,也就是,你必须首先用 WSACreateEvent() 来创建一个事件对象,然后调用 WSAEventSelect() 来使得 Socket 的事件和这个事件对象关联。最终你将要在一个线程里用 WSAWaitForMultipleEvents() 来等待这个事件对象被触发。这个过程也稍显复杂。



 

1、快速通信

Winsock的Nagle算法将降低小数据报的发送速度,而系统默认是使用Nagle算法。

例子:
SOCKET sConnect = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

int bNodelay = 1;

setsockopt(

sConnect,

IPPROTO_TCP,

TCP_NODELAY,

(char *)&bNodelay,

sizoeof(bNodelay));//不采用延时算法

 

 

2、SOCKET的SegMentSize和收发缓冲

 

TCPSegMentSize是发送接受时单个数据报的最大长度,系统默认为1460,收发缓冲大小为8192。

   在SOCK_STREAM方式下,如果单次发送数据超过1460,系统将分成多个数据报传送,在对方接受到的将是一个数据流,应用程序需要增加断帧的判 断。当然可以采用修改注册表的方式改变1460的大小,但MicrcoSoft认为1460是最佳效率的参数,不建议修改。

   在工控系统中,建议关闭Nagle算法,每次发送数据小于1460个字节(推荐1400),这样每次发送的是一个完整的数据报,减少对方对数据流的断帧处 理。

 

3. 改变TCP收发缓冲区大小

系统默认为8192,利用如下方式可改变。

SOCKET sConnect = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

int nrcvbuf=1024*20;

setsockopt(

sConnect,

SOL_SOCKET,

SO_SNDBUF,//写缓冲,读缓冲为SO_RCVBUF

(char *)&nrcvbuf,

sizeof(nrcvbuf));

在设置缓冲时,检查是否真正设置成功用

int getsockopt(

SOCKET s,

int level,

int optname,

char FAR *optval,

int FAR *optlen

);

 

4. 同步方式中减少断网时connect函数的阻塞时间

同步方式中的断网时connect的阻塞时间为20秒左右 ,可采用gethostbyaddr事先判断到服务主机的路径是否是通的,或者先ping一下对 方主机的IP地址。

 

同步方式中的断网时connect的阻塞时间为20秒左右,可采用gethostbyaddr事先判断到服务主机的路径是否是通的,或者先ping一下对 方主机的IP地址。

   A、采用gethostbyaddr阻塞时间不管成功与否为4秒左右。

   例子:

LONG lPort=3024;

struct sockaddr_in ServerHostAddr;//服务主机地址

ServerHostAddr.sin_family=AF_INET;

ServerHostAddr.sin_port=::htons(u_short(lPort));

ServerHostAddr.sin_addr.s_addr=::inet_addr("192.168.1.3");

HOSTENT* pResult=gethostbyaddr((const char *) &

(ServerHostAddr.sin_addr.s_addr),4,AF_INET);

if(NULL==pResult)

{

int nErrorCode=WSAGetLastError();

TRACE("gethostbyaddr errorcode=%d",nErrorCode);

}

else

{

TRACE("gethostbyaddr %s/n",pResult->h_name);;

}

B、采用PING方式时间约2秒左右

 

5、同步方式中解决recv,send阻塞问题

   采用select函数解决,在收发前先检查读写可用状态。

 

6.服务方同一端口多IP地址的bind和listen

在可靠性要求高的应用中,要求使用双网和多网络通道,再服务方很容易实现,用如下方式可建立客户对本机所有IP地址在端口3024下的请求服务。

 

SOCKET hServerSocket_DS=INVALID_SOCKET;

struct sockaddr_in HostAddr_DS;//服务器主机地址

LONG lPort=3024;

HostAddr_DS.sin_family=AF_INET;

HostAddr_DS.sin_port=::htons(u_short(lPort));

HostAddr_DS.sin_addr.s_addr=htonl(INADDR_ANY);

hServerSocket_DS=::socket( AF_INET, SOCK_STREAM,IPPROTO_TCP);

if(hServerSocket_DS==INVALID_SOCKET)

{

AfxMessageBox("建立数据服务器SOCKET 失败!");

return FALSE;

}

if(SOCKET_ERROR==::bind(hServerSocket_DS,(struct

sockaddr *)(&(HostAddr_DS)),sizeof(SOCKADDR)))

{

int nErrorCode=WSAGetLastError ();

TRACE("bind error=%d/n",nErrorCode);

AfxMessageBox("Socket Bind 错误!");

return FALSE;

}

if(SOCKET_ERROR==::listen(hServerSocket_DS,10))//10个客户

{

AfxMessageBox("Socket listen 错误!");

return FALSE;

}

AfxBeginThread(ServerThreadProc,NULL,THREAD_PRIORITY_NORMAL);
在客户方要复杂一些,连接断后,重联不成功则应换下一个IP地址连接。也可采用同时连接好后备用的方式。

 

 

你可能感兴趣的:(Winsock 同步方式 编程要点)