• windows套接字阻塞模式编程实例


    一、阻塞模式套接字服务端和客户端的运行流程如下:

    1.1 服务器运行过程如下:

    1.服务器启动后,等待客户端的连接请求。
    2.当收到客户端的请求后,在界面上显示该客户端的IP地址和端口,以及“Hello,Server!”问候语。
    3.服务器向该客户端应答“Hello,Clinet!”问候语。
    4.服务器退出。
    1.2客户端运行过程如下:
    1.客户端启动后,向服务器发起连接请求。
    2.当连接请求被接受后,客户端向服务器发送“Hello,Server!”问候语。
    3.等待服务器的应答。
    4.当客户端收到服务器的“Hello,Clinet!”应答后,客户端退出。

    1.3 客户端和服务器端工作流程如下:

    二、实例

    2.1 服务器端:Server.cpp

      1 #include<iostream>
      2 #include<winsock2.h>
      3 #include<string>
      4 #pragma comment(lib,"ws2_32.lib")
      5 using namespace std;
      6 
      7 #define SERVER_EXIT_OK            0
      8 #define SERVER_DLL_ERROR        1
      9 #define SERVER_API_ERROR        2
     10 #define SERVERPORT                    8888
     11 #define MAX_NUM_BUF                64
     12 
     13 //全局变量
     14 char bufRecv[MAX_NUM_BUF];//读缓冲区
     15 char bufSend[MAX_NUM_BUF];//写缓冲区
     16 SOCKET sServer;//服务器监听套接字
     17 SOCKET sClient;//接受客户端套接字
     18 bool bConning;//与客户端的连接状态变量
     19 
     20 //函数
     21 void InitMember(void);
     22 void ShowSocketMsg(char* str);
     23 int HandleSocketError(char* str);
     24 BOOL RecvLine(SOCKET s, char *buf);//读取一行数据
     25 BOOL SendLine(SOCKET s,char * buf);//发送一行数据
     26 int ExitClient(int nExit);//退出程序
     27 
     28 int main(int argc,char*argv[])
     29 {
     30     //调用初始化函数,进行相关初始化工作
     31     InitMember();
     32     //Windows Sockets动态库初始化
     33     WORD            wVersionRequseted;
     34     WSADATA    wsaData;
     35     int                retVal;
     36     wVersionRequseted = MAKEWORD(2,2);
     37     retVal = WSAStartup(wVersionRequseted,&wsaData);
     38     if (retVal!=0)
     39     {
     40         ShowSocketMsg("初始化动态连接库失败");
     41         return SERVER_DLL_ERROR;
     42     }
     43     //确保Winsock dll支持2.2
     44     if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion!=2))
     45     {
     46         ShowSocketMsg("没有发现动态链接库");
     47         return SERVER_DLL_ERROR;
     48     }
     49     //创建套接字
     50     sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     51     if (INVALID_SOCKET==sServer)
     52     {
     53         return HandleSocketError("Faild socket()!");
     54     }
     55     //服务器套接字地址
     56     SOCKADDR_IN addrServer;
     57     addrServer.sin_family = AF_INET;
     58     addrServer.sin_port = htons(SERVERPORT);
     59     addrServer.sin_addr.S_un.S_addr = INADDR_ANY;
     60     //绑定套接字
     61     retVal = bind(sServer,(sockaddr*)&addrServer,sizeof(addrServer));
     62     if (SOCKET_ERROR==retVal)
     63     {
     64         closesocket(sServer);
     65         return HandleSocketError("绑定套接字失败");
     66     }
     67     //监听
     68     retVal = listen(sServer,5);
     69     if (SOCKET_ERROR==retVal)
     70     {
     71         closesocket(sServer);
     72         return HandleSocketError("监听失败");
     73     }
     74     cout << "服务器开始初始化成功!" << endl;
     75     cout << "等待客户端的连接...." << endl;
     76     //接受客户端的请求
     77     sockaddr_in addrClient;
     78     int addrClientLen = sizeof(addrClient);
     79     sClient = accept(sServer,(sockaddr*)&addrClient,&addrClientLen);
     80     if (SOCKET_ERROR==sClient)
     81     {
     82         closesocket(sServer);
     83         return HandleSocketError("接受客户端请求失败");
     84     }
     85     //显示客户端的IP和端口
     86     char *pClientIP = inet_ntoa(addrClient.sin_addr);
     87     u_short clientPort = ntohs(addrClient.sin_port);
     88     cout << "接受到来自客户端的请求:" << endl;
     89     cout << "客户端的IP:" << pClientIP << endl;
     90     cout << "客户端的端口:" << clientPort << endl;
     91     //接受客户端的数据
     92     if (!RecvLine(sClient,bufRecv))
     93     {
     94         return ExitClient(SERVER_API_ERROR);
     95     }
     96     //显示客户端的数据
     97     cout << bufRecv << endl;
     98     //向客户端发送数据
     99     strcpy(bufSend,"hello,client!
    ");
    100     if (!SendLine(sClient,bufSend))
    101     {
    102         return ExitClient(SERVER_API_ERROR);
    103     }
    104     //显示退出信息
    105     cout << "服务器正在退出>>>>>" << endl;
    106     //退出
    107     return ExitClient(SERVER_EXIT_OK);
    108     getchar();
    109     return 0;
    110 }
    111 
    112 
    113 //初始化成员变量
    114 void InitMember(void)
    115 {
    116     //初始化缓冲区
    117     memset(bufRecv, 0, MAX_NUM_BUF);
    118     memset(bufSend, 0, MAX_NUM_BUF);
    119     //初始化
    120     sServer = INVALID_SOCKET;
    121     sClient = INVALID_SOCKET;
    122     //无连接状态
    123     bConning = FALSE;
    124 
    125 }
    126 void ShowSocketMsg(char* str)
    127 {
    128     MessageBox(NULL,(LPCWSTR)str,(LPCWSTR)"SERVER_ERROR",MB_OK);
    129 }
    130 
    131 int HandleSocketError(char * str)
    132 {
    133     ShowSocketMsg(str);//显示错误
    134     WSACleanup();//卸载Windows socket DLL
    135     return SERVER_API_ERROR;//退出应用程序
    136 }
    137 
    138 BOOL RecvLine(SOCKET s, char * buf)
    139 {
    140     BOOL retVal=TRUE;                                //返回值
    141     BOOL bLineEnd = FALSE;            //行结束
    142     int    nReadLen = 0;                        //读入字节数
    143     int    nDataLen = 0;                        //数据长度
    144     while (!bLineEnd&&bConning)    //与客户端连接,没有换行
    145     {
    146         nReadLen = recv(s,buf+nDataLen,1,0);
    147         //错误处理
    148         if (SOCKET_ERROR==nReadLen)
    149         {
    150             int nErrorCode = WSAGetLastError();
    151             if (WSAENOTCONN==nErrorCode)
    152             {
    153                 ShowSocketMsg("套接字未连接");
    154             }
    155             else if (WSAESHUTDOWN==nErrorCode)
    156             {
    157                 ShowSocketMsg("套接字已经关闭");
    158             }
    159             else if (WSAETIMEDOUT == nErrorCode)
    160             {
    161                 ShowSocketMsg("连接已断开!");
    162             }
    163             else if (WSAECONNRESET == nErrorCode)
    164             {
    165                 ShowSocketMsg("一个现存的远程主机上运行的客户端被强制关闭!");
    166             }
    167             else {}
    168 
    169             retVal = FALSE;    //读数据失败
    170             break;    
    171         }
    172 
    173         if (nReadLen==0)//客户端关闭
    174         {
    175             retVal = FALSE;
    176             break;
    177         }
    178         //读入数据
    179         if (*(buf+nDataLen)=='
    ')
    180         {
    181             bLineEnd = TRUE;//接受数据结束
    182         }
    183         else
    184         {
    185             nDataLen += nReadLen;//增加数据长度
    186         }
    187     }
    188     
    189     return retVal;
    190 }
    191 
    192 BOOL SendLine(SOCKET s, char * buf)
    193 {
    194     int retVal=0;//返回值
    195     retVal = send(s, buf, strlen(buf), 0);//一次发送
    196 //错误处理
    197     if (SOCKET_ERROR == retVal)
    198     {
    199         int nErrCode = WSAGetLastError();//错误代码
    200         if (WSAENOTCONN == nErrCode)
    201         {
    202             ShowSocketMsg("套接字未连接");
    203 
    204         }
    205         else if (WSAESHUTDOWN == nErrCode)
    206         {
    207             ShowSocketMsg("套接字已关闭!");
    208 
    209         }
    210         else if (WSAETIMEDOUT == nErrCode)
    211         {
    212             ShowSocketMsg("连接已断开!");
    213         }
    214         else {}
    215 
    216         return FALSE;    //发送失败
    217     }
    218 
    219     return TRUE;
    220 }
    221 
    222 int ExitClient(int nExit)
    223 {
    224     closesocket(sServer);    //关闭监听套接字
    225     closesocket(sClient);    //关闭连接客户端套接接
    226     WSACleanup();            //卸载Windows sockets DLL 清理内存
    227     return nExit;            //退出
    228 }

    2.2 客户端:Client.cpp

      1 #include <windows.h>
      2 #include <winsock.h>
      3 #include <iostream>
      4 #pragma comment(lib, "wsock32.lib")
      5 using namespace std;
      6 
      7 
      8 #define CLIENT_EXIT_OK                0    //客户端正常退出
      9 #define CLIENT_DLL_REEOR            1    //调用Windows socket dll失败
     10 #define CLIENT_API_ERROR            2    //调用Windows socket api失败
     11 #define MAX_NUM_BUF                    64    //缓冲区的最大长度
     12 #define    SERVERPORT                    8888//服务器TCP端口
     13 
     14 
     15 //变量
     16 char    bufRecv[MAX_NUM_BUF];                        //读缓冲区
     17 char    bufSend[MAX_NUM_BUF];                        //写缓冲区
     18 SOCKET    sHost;                                                //socket
     19 BOOL    bConning;                                            //连接服务器状态
     20 
     21 //函数
     22 void    InitMember(void);                                    //初始化变量
     23 int        ExitClient(int nExit);                            //退出
     24 BOOL    RecvLine(SOCKET s, char* buf);        //读取一行数据
     25 void    ShowErrorMsg(void);                                //显示错误信息
     26 
     27 //主函数
     28 int main()
     29 {
     30 
     31     //初始化变量
     32     InitMember();
     33 
     34     WORD    wVersionRequested;                            //应用程序需要Windows sockets DLL的版本
     35     WSADATA    wsaData;                                        //Windows sockets DLL版本信息
     36     int        retVal=0;                                                    //调用Windows sockets API返回值
     37 
     38     //初始化Windows Sockets DLL
     39     wVersionRequested = MAKEWORD(2, 2);
     40     retVal = WSAStartup(wVersionRequested, (LPWSADATA)&wsaData);
     41     if (0 != retVal)
     42     {
     43         MessageBox(NULL, (LPCWSTR)"初始化动态链接库失败!",(LPCWSTR) "ERROR", MB_OK);
     44         return CLIENT_DLL_REEOR;
     45     }
     46 
     47 
     48     //创建Windows socket
     49     sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     50     if (INVALID_SOCKET == sHost)
     51     {
     52         ShowErrorMsg();            //显示错误信息
     53         WSACleanup();            //释放资源
     54         return CLIENT_API_ERROR;//退出
     55     }
     56 
     57     //准备连接服务器
     58     cout << "客户端初始化成功!" << endl;
     59     cout << "准备连接到服务器..." << endl;
     60 
     61 
     62 
     63     //获取主机的信息
     64     LPHOSTENT hostEntry;
     65     char hostname[MAX_NUM_BUF];
     66     gethostname(hostname, MAX_NUM_BUF);            //获取主机名称
     67     hostEntry = gethostbyname(hostname);        //获取主机信息
     68     if (!hostEntry)
     69     {
     70         ShowErrorMsg();                        //显示错误信息
     71         return ExitClient(CLIENT_API_ERROR);    //退出
     72     }
     73     //设置sockaddr_in
     74     SOCKADDR_IN addrServ;
     75     addrServ.sin_family = AF_INET;
     76     addrServ.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
     77     addrServ.sin_port = htons(SERVERPORT);
     78     //连接服务器
     79     retVal = connect(sHost, (sockaddr*)&addrServ, sizeof(addrServ));
     80     if (SOCKET_ERROR == retVal)
     81     {
     82         ShowErrorMsg();                        //显示错误信息
     83         return ExitClient(CLIENT_API_ERROR);    //退出
     84     }
     85     else {
     86         bConning = TRUE;                    //连接服务器成功
     87     }
     88     //连接服务器成功
     89     cout << "连接服务器成功!" << endl;
     90 
     91 
     92     //向服务器发送数据
     93     strcpy_s(bufSend, "Hello,Server!
    ");
     94     retVal = send(sHost, bufSend, strlen(bufSend), 0);
     95     if (SOCKET_ERROR == retVal)
     96     {
     97         ShowErrorMsg();                        //显示错误信息
     98         return ExitClient(CLIENT_API_ERROR);    //退出
     99     }
    100 
    101     //从服务器接收数据
    102     if (!RecvLine(sHost, bufRecv))
    103     {
    104         ShowErrorMsg();                        //显示错误信息
    105         return ExitClient(CLIENT_API_ERROR);    //退出
    106     }
    107     //显示服务器的应答
    108     cout << bufRecv << endl;
    109 
    110     //退出
    111     return ExitClient(CLIENT_EXIT_OK);
    112 }
    113 
    114 
    115 /*
    116 *    显示错误信息
    117 */
    118 void    ShowErrorMsg(void)
    119 {
    120     int nErrCode = WSAGetLastError();//获取错误代码
    121 
    122     HLOCAL hlocal = NULL;
    123 
    124     //获取错误的文本字符串
    125     BOOL fOk = FormatMessage(
    126         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
    127         NULL, nErrCode, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
    128         (PTSTR)&hlocal, 0, NULL);
    129 
    130     //显示错误信息
    131     if (hlocal != NULL)
    132     {
    133         MessageBox(NULL, (LPCWSTR)LocalLock(hlocal), (LPCWSTR)"CLIENT ERROR", MB_OK);
    134         LocalFree(hlocal);
    135     }
    136 }
    137 
    138 
    139 /*
    140 *    初始化成员变量
    141 */
    142 void    InitMember(void)
    143 {
    144     //初始化读和写缓冲区
    145     memset(bufRecv, 0, MAX_NUM_BUF);
    146     memset(bufSend, 0, MAX_NUM_BUF);
    147     //初始化
    148     sHost = INVALID_SOCKET;
    149     //没有连接状态
    150     bConning = FALSE;
    151 }
    152 
    153 /*
    154 *    退出
    155 */
    156 int        ExitClient(int nExit)
    157 {
    158     closesocket(sHost);        //关闭套接字
    159     WSACleanup();            //卸载Windows sockets DLL 清理内存
    160 
    161                             //显示退出信息
    162     cout << "客户端正在退出..." << endl;
    163     Sleep(20000);
    164     return nExit;    //退出
    165 }
    166 
    167 
    168 /*
    169 *    读取一行数据
    170 */
    171 BOOL    RecvLine(SOCKET s, char* buf)
    172 {
    173     BOOL    retVal = TRUE;            //返回值
    174     BOOL    bLineEnd = FALSE;        //行结束
    175     int        nReadLen = 0;            //读入字节数
    176     int        nDataLen = 0;            //数据长度
    177     while (!bLineEnd && bConning)    //与客户端连接 没有换行
    178     {
    179         nReadLen = recv(s, buf + nDataLen, 1, 0);//每次接收一个字节        
    180                                                  //错误处理
    181         if (SOCKET_ERROR == nReadLen)
    182         {
    183             retVal = FALSE;    //读数据失败
    184             break;            //跳出循环                        
    185         }
    186 
    187         if (0 == nReadLen)//客户端关闭
    188         {
    189             retVal = FALSE;    //读数据失败
    190             break;            //跳出循环            
    191         }
    192 
    193         //读入数据
    194         if ('
    ' == *(buf + nDataLen))    //换行符
    195         {
    196             bLineEnd = TRUE;            //接收数据结束
    197         }
    198         else {
    199             nDataLen += nReadLen;        //增加数据长度
    200         }
    201     }
    202 
    203     return retVal;
    204 }
  • 相关阅读:
    【板+背包】多重背包 HDU Coins
    【板+并查集判断连通性】并查集判断连通性
    【Dijstra堆优化】HDU 3986 Harry Potter and the Final Battle
    【区间筛】2017多校训练四 HDU6069 Counting Divisors
    【构造+DFS】2017多校训练三 HDU 6060 RXD and dividing
    【链表】2017多校训练三 HDU 6058 Kanade's sum
    【带权并查集】HDU 3047 Zjnu Stadium
    【优先级队列】 Holedox Eating
    ajax学习笔记3-jQuery实现ajax(大拇指向上)
    ajax学习笔记2-JSON形式返回(大拇指向上)
  • 原文地址:https://www.cnblogs.com/506941763lcj/p/11408992.html
Copyright © 2020-2023  润新知