winSockets编程阻塞模式(服务端)

Posted YuRi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了winSockets编程阻塞模式(服务端)相关的知识,希望对你有一定的参考价值。

在阻塞模式下,在I/O操作完成前,执行的操作函数将一直等候而不会立即返回,该函数所在的线程会阻塞在这里。相反,在非阻塞模式下,套接字函数立即返回,而不管I/O是否完成。

#生产者和消费者模式

##

服务器端的简化形式(#这套流程需要完全背诵#

/*****************初始化***********************/
int retVal;
WSAData wsd;
retVal = WSAStartup(MAKEWORD(1, 1), &wsd);
/****************************************/

//创建套接字
sSever = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

/************绑定套接字****************************/
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(5999);
addrServ.sin_addr.s_addr = INADDR_ANY;
retVal = bind(sSever, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
/****************************************/

//监听
retVal = listen(sSever, 1);

/***************获取客户端请求,线程在阻塞************************/
SOCKADDR_IN addrClient;
int addrClientlen = sizeof(addrClient);
sClient = accept(sSever, (sockaddr FAR*)&addrClient, &addrClientlen);
/***************************************/

while (true) //从接收缓冲区中读取数据,每次一个字节;
{
    nReadLen = recv(s, buf + nDataLen, 1, 0);
  ........ } retVal
= send(s, str, strlen(str), 0); //发送数据(一次发送)

#完整代码#

#include <iostream>
#include <WINSOCK2.H>
#pragma comment(lib, "wsock32.lib")

#define SERVER_EXIT_OK              0        //服务器正常退出;
#define SERVER_DLL_REEOR            1        //调用Windows sockets DLL失败;
#define SERVER_API_ERROR            2        //调用Windows sockets API失败;
#define SERVERPORT                  5555     //服务器TCP端口;

char    bufRecv[MAX_PATH];                    //读缓冲区;
char    bufSend[MAX_PATH];                    //写缓冲区;
SOCKET  sServer;                              //服务器监听套接字;
SOCKET  sClient;                              //接受客户端套接字;
BOOL    bConning;                             //与客户端的连接状态;

void    InitMember(void);                    //初始化成员变量; 
int     ExitClient(int nExit);                //客户端退出;
BOOL    RecvLine(SOCKET s, char* buf);        //读取一行数据;
BOOL    SendLine(SOCKET s, char* buf);        //发送一行数据;
int     HandleSocketError(char *str);        //对Windows sockets API调用错误处理;
void    ShowSocketMsg(char* str);            //显示错误信息;

int main(int argc, char* argv[])
{
    InitMember();
    WSADATA    wsaData;                //Windows sockets DLL版本信息
    int        retVal;                    //调用Windows sockets API返回值        
    retVal = WSAStartup(MAKEWORD(1, 1), &wsaData);
    if (0 != retVal)
    {
        ShowSocketMsg("找不到可用的Socket DLL!");
        return SERVER_DLL_REEOR;
    }
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
    {
        ShowSocketMsg("Can not find a usable Windows Sockets dll!");
        WSACleanup();
        return SERVER_DLL_REEOR;
    }

    //创建套接字;
    /*******************************************************/
    sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == sServer)
    {
        return HandleSocketError("Failed socket()!");
    }
    /********************************************************/

    //服务器套接字地址;
    SOCKADDR_IN addrServ;
    addrServ.sin_family = AF_INET;
    addrServ.sin_port = htons(SERVERPORT);
    addrServ.sin_addr.s_addr = INADDR_ANY;

    retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));//绑定套接字;

    if (SOCKET_ERROR == retVal)
    {
        closesocket(sServer);
        return HandleSocketError("Failed bind()!");
    }

    retVal = listen(sServer, 1);//开始监听; 
    if (SOCKET_ERROR == retVal)
    {
        closesocket(sServer);
        return HandleSocketError("Failed listen()!");
    }
        
    std::cout << "Server succeeded!" <<std::endl;//等待客户端的连接;
    std::cout << "Waiting for new clients..." <<std::endl;

    /***********接受客户端请求****************************/
    sockaddr_in addrClient;
    int addrClientlen = sizeof(addrClient);
    sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);
    if (INVALID_SOCKET == sClient)
    {
        closesocket(sServer);
        return HandleSocketError("Failed accept()!");
    }
    else
    {
        bConning = TRUE;//客户端请求成功;
    }

    //显示客户端的IP和端口;
    char *pClientIP = inet_ntoa(addrClient.sin_addr);
    u_short  clientPort = ntohs(addrClient.sin_port);
    std::cout << "Accept a client." <<std::endl;
    std::cout << "IP: " << pClientIP <<std::endl;
    std::cout << "Port: " << clientPort <<std::endl;
    
    if (!RecvLine(sClient, bufRecv))//接收客户端数据;
    {
        return    ExitClient(SERVER_API_ERROR);
    }
    
    std::cout << bufRecv <<std::endl;//显示客户端数据;
    
    strcpy_s(bufSend, "Hello,Client!\n");//向客户端发送数据;
    if (!SendLine(sClient, bufSend))
    {
        return    ExitClient(SERVER_API_ERROR);
    }
    std::cout << "Server exiting..." <<std::endl;//显示退出信息;
    return ExitClient(SERVER_EXIT_OK);
}

void InitMember(void)
{    
    memset(bufRecv, 0, MAX_PATH);
    memset(bufSend, 0, MAX_PATH);
    sServer = INVALID_SOCKET;
    sClient = INVALID_SOCKET;    
    bConning = FALSE;
}

int ExitClient(int nExit)
{
    closesocket(sServer);
    closesocket(sClient);
    WSACleanup();
    return nExit;
}

BOOL RecvLine(SOCKET s, char* buf)
{
    BOOL    retVal = TRUE;            //返回值
    BOOL    bLineEnd = FALSE;        //行结束
    int        nReadLen = 0;            //读入字节数
    int        nDataLen = 0;            //数据长度
    while (!bLineEnd && bConning)    //与客户端连接 没有换行
    {
        nReadLen = recv(s, buf + nDataLen, 1, 0);//每次接收一个字节

        //错误处理
        if (SOCKET_ERROR == nReadLen)
        {
            int nErrCode = WSAGetLastError();//错误代码
            if (WSAENOTCONN == nErrCode)
            {
                ShowSocketMsg("The socket is not connected!");

            }
            else if (WSAESHUTDOWN == nErrCode)
            {
                ShowSocketMsg("The socket has been shut down!");

            }
            else if (WSAETIMEDOUT == nErrCode)
            {
                ShowSocketMsg("The connection has been dropped!");
            }
            else if (WSAECONNRESET == nErrCode)
            {
                ShowSocketMsg("The virtual circuit was reset by the remote side!");
            }
            else
            {
            }

            retVal = FALSE;    //读数据失败
            break;            //跳出循环                        
        }


        if (0 == nReadLen)//客户端关闭
        {
            retVal = FALSE;    //读数据失败
            break;            //跳出循环            
        }

        //读入数据
        if (\n == *(buf + nDataLen))    //换行符
        {
            bLineEnd = TRUE;            //接收数据结束
        }
        else
        {
            nDataLen += nReadLen;        //增加数据长度
        }
    }

    return retVal;
}

BOOL SendLine(SOCKET s, char* str)
{
    int retVal;//返回值
    retVal = send(s, str, strlen(str), 0);//一次发送

    //错误处理
    if (SOCKET_ERROR == retVal)
    {
        int nErrCode = WSAGetLastError();//错误代码
        if (WSAENOTCONN == nErrCode)
        {
            ShowSocketMsg("The socket is not connected!");

        }
        else if (WSAESHUTDOWN == nErrCode)
        {
            ShowSocketMsg("The socket has been shut down!");

        }
        else if (WSAETIMEDOUT == nErrCode)
        {
            ShowSocketMsg("The connection has been dropped!");
        }
        else
        {
        }

        return FALSE;    //发送失败
    }

    return TRUE;        //发送成功
}

int HandleSocketError(char *str)
{
    ShowSocketMsg(str);        //显示错误消息    
    WSACleanup();            //卸载Windows socket DLL    
    return SERVER_API_ERROR;//退出应用程序
}

void ShowSocketMsg(char* str)
{
    MessageBox(NULL, str, "SERVER ERROR", MB_OK);
}

 

以上是关于winSockets编程阻塞模式(服务端)的主要内容,如果未能解决你的问题,请参考以下文章

Netty——网络编程(阻塞理解及代码示例)

Netty——网络编程(阻塞理解及代码示例)

Netty——网络编程(非阻塞理解及代码示例)

Netty——网络编程(非阻塞理解及代码示例)

Winsocket编程之域名解析

winsocket UDP “使用了与请求的协议不兼容的地址”错误