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!\n");
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)=='\n')
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!\n");
 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 ('\n' == *(buf + nDataLen))    //换行符
195         {
196             bLineEnd = TRUE;            //接收数据结束
197         }
198         else {
199             nDataLen += nReadLen;        //增加数据长度
200         }
201     }
202 
203     return retVal;
204 }

 

posted on 2019-08-25 19:31  lfylcj  阅读(626)  评论(0编辑  收藏  举报

导航