非阻塞套接字用法

http://www.cppblog.com/yunboy4/archive/2010/03/16/91231.html

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

    WSAData Data;
    WSAStartup(MAKEWORD(2, 2), &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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值