随笔-5  评论-1  文章-0  trackbacks-0

 

1.非阻塞套接字的模式
(
1)服务器端
    通常socket运行后默认为阻塞模式。要调用ioctlsocket函数设置非阻塞模式。
如:

    WSAData Data;
    WSAStartup(MAKEWORD(
22), &Data);
    SerSocket 
= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
if(INVALID_SOCKET == SerSocket)
        cout
<<"Invalid Socket!\n";
    u_long iMode 
= 1;
    ioctlsocket(SerSocket, FIONBIO, 
&iMode);
    
    在接受客户端请求的线程中,若接受成功就返回客户端的套接字,否则返回INVALID_SOCKET错误,
若错误代码为WSAEWOULDBLOCK,说明当前没有客户端请求。
如:
//接受客户端请求线程
DWORD WINAPI AcceptClientPro(LPVOID LpP)
{
    SOCKADDR_IN ClientAdrr;
    
int AddrLen = sizeof(SOCKADDR);
    
//非阻塞模式
    while (!IsConnet)
    {
        ClientSock 
= accept(SerSocket, (SOCKADDR *)&ClientAdrr, &AddrLen );
        
if(INVALID_SOCKET == ClientSock)
        {
            
int n = WSAGetLastError();
            
//没有客户端请求
            if(WSAEWOULDBLOCK == n)    
            {
                cout
<<"没有客户端发出请求!"<<endl;
                Sleep(
1000);
                
continue;
            }
else
            {
                cout
<<"出现错误!"<<endl;
                Sleep(
1000);
            }
        }
else
        {
            cout
<<"已连接客户端!"<<endl;
            IsConnet 
= true;
            
break;
        }
    }
    
return 0;
}
    
    就recv函数来说,在阻塞模式中,如果没有客户端发送数据过来,线程到这里会阻塞,直到有数
据发送过来为止。在非阻塞模式中,没有客户端发送数据过来,返回SOCKER_ERROR,错误代码为WSAEWOULDBLOCK。
如:
//接收数据线程
DWORD WINAPI ReceiveDataPro(LPVOID LpP)
{
    
while(!IsConnet);        //保证连接后再接受数据
    while(1)
    {
        
if(IsReadyRecei)        //保证缓冲区在未处理时不受新来的数据的影响
        {
            
            
int ReceiLen = recv(ClientSock, (char *)&DataPack, sizeof(DataPack), 0);
            
if(SOCKET_ERROR == ReceiLen)
            {
                
int Err = WSAGetLastError();
                
if(WSAEWOULDBLOCK == Err)
                {
                    cout
<<"没有收到数据"<<endl;
                    
continue;
                }
                
else if (WSAENETDOWN == Err ||//客户端关闭了连接
                    WSAETIMEDOUT == Err ||
                    WSAECONNRESET 
== Err )    
                {
                    cout
<<"服务器关闭了连接"<<endl;
                    
break;
                }
            }
            
if(0 == ReceiLen)        //客户端关闭了连接
            {
                cout
<<"ReceiLen = 0"<<endl;
                
break;
            }
            
if(ReceiLen >= sizeof(DataPack))        //成功接收
            {
                cout
<<"已收到数据:"<<DataPack.buf<<endl;
                IsReadyRecei 
= false;
                
break;
            }
        }
    }
    
return 0;
}    

(
2)客户端
    在客户端的连接请求线程中,connect函数会返回SOCKET_ERROR,这并不是说明连接失败,具体情况
要看它的WSAGetLastError()返回值,若它三次返回SOCKET_ERROR的Error代码依次为WSAEWOULDBLOCK,
WSAEINVAL,WSAEISCONN,就说明连接服务器成功,否则失败。但有的时候WSAEINVAL没有出现就有WSAEISCONN
了,所以我还是以WSAEISCONN为连接完成的标志,但要注意其实在三次返回代码中,第一次的WSAEWOULDBLOCK
之前的connect操作就成功了,如果没出意外服务器就要响应了。
如:
//连接服务器线程
DWORD WINAPI ConnetServerPro(LPVOID LpP)
{
    SOCKADDR_IN ServerAddr;
    ServerAddr.sin_family 
= AF_INET;
    ServerAddr.sin_port 
= htons(1200);
    ServerAddr.sin_addr.s_addr 
= inet_addr("192.168.1.100");
    
int BlockFlag = 0;
    
int InvalFlag = 0;
    
while (!IsConnet)
    {
        
int nResu = connect(ClientSock, (SOCKADDR *)&ServerAddr, sizeof(SOCKADDR));
        
if(SOCKET_ERROR == nResu)
        {
            
int n = WSAGetLastError();
            
            
if(WSAEWOULDBLOCK == n )        //不能立即完成
            {
                cout
<<"过程1!"<<endl;
                BlockFlag
++;
                
continue;
            }
            
else if(WSAEINVAL == n)        //监听状态
            {
                cout
<<"过程2!"<<endl;
                InvalFlag
++;
                
continue;
            }
            
else if(WSAEISCONN == n)        //连接完成
            {
                cout
<<"已连接服务器!"<<endl;
                IsConnet 
= true;
                
break;
            }
            
else 
            {
                cout
<<"出现其他错误!\n"<<endl;
                Sleep(
1000);
            }
        }
    }

    
return 0;
}

    在发送数据线程中,send()返回的是发送数据的长度说明发送成功;返回SOCKET_ERROR时,若
错误代码为WSAEWOULDBLOCK就再重试,不是WSAEWOULDBLOCK就说明有错误。】
如:
//发送数据线程
DWORD WINAPI SendDataPro(LPVOID LpP)
{
    
while(!IsConnet);    //保证已连接服务器
    while(1)
    {
        
int len = send(ClientSock, (char *)&DataPack, DataPack.Head.len, 0);
        
if(SOCKET_ERROR == len)
        {
            
int Error = WSAGetLastError();
            
if(WSAEWOULDBLOCK == Error)
                
continue;
        }
        
else        //发送成功
        {
            cout
<<"发送成功!"<<endl;
            
break;
        }
    }

    
return 0;
}
posted on 2009-07-26 11:13 yunboy 阅读(2050) 评论(1)  编辑 收藏 引用 所属分类: 网络通信

评论:
# re: 非阻塞套接字的模式 2010-03-16 10:39 | FB
非阻塞套接字 客户端为什么没有讲接受函数  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理