Winsock 同步方式 编程要点
2010-03-24 08:31
148 查看
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地址连接。也可采用同时连接好后备用的方式。
、默认用作同步阻塞方式
,
那就是当你从不
调用
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地址连接。也可采用同时连接好后备用的方式。
相关文章推荐
- 运用C#编程通过OPC方式实现PC机与西门子PLC通讯-同步通讯篇[转]
- boost::asio的同步方式和异步方式网络编程
- Windows编程-- 用户方式中线程的同步---关键代码段(临界区)
- C/C++ 多线程(MultiThread)编程及几种同步方式
- TCP/IP Winsock编程要点
- C++ 串口编程 写串口 同步通信方式
- 采用用同步编程的方式实现跨进程异步获取数据[一]
- TCP/IP Winsock编程要点
- 运用C#编程通过OPC方式实现PC机与西门子PLC通讯-同步通讯篇
- 网络编程中同步、异步、阻塞和非阻塞四种调用方式的区别
- TCP/IP Winsock编程要点
- 【面试必读(编程基础)】网络游戏同步方式(帧同步和状态同步)
- TCP/IP Winsock编程要点
- 同步与异步 阻塞与非阻塞 WinSock编程
- 采用用同步编程的方式实现跨进程异步获取数据[二]-创建玩家账号和获取角色列表
- java Thread编程(三) 同步的两种不同实现方式
- TCP/IP Winsock编程要点
- 多线程编程之Windows同步方式
- GCD编程dispatch_sync(同步)和dispatch_async(异步)方式执行并发队列任务区别
- TCP/IP Winsock编程要点