C++基礎--完善Socket C/S ,實現客戶端,服務器端斷開重連


  1 // WindowsSocketServer.cpp : 定義控制台應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <iostream>
  6 #include <string>
  7 #include <Windows.h>
  8 #include <Winsock2.h>
  9 #include <fstream>
 10 #pragma comment(lib,"Ws2_32.lib")
 11 
 12 using namespace std;
 13 #define PORT 8080
 14 #define IP_ADDRESS "172.16.20.181"
 15 CRITICAL_SECTION cs;
 16 //#define CLIENT_PORT 8081
 17 ///#define CLIENT_IP_ADDRESS "172.16.20.181"
 18 
 19 //接收每個客戶端連接的處理函數
 20 DWORD WINAPI ClientThread(LPVOID lpParameter);
 21 
 22 //連接和服務器端有連接的客戶端
 23 DWORD WINAPI ConnectClientsThread(LPVOID lpParameter);
 24 
 25   int main(int argc, char* argv[])
 26   {
 27       //HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 28       //SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN); 
 29       InitializeCriticalSection(&cs);
 30       //初始化事件和關鍵段,自動置位,初始無觸發的匿名事件
 31       //g_hThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
 32 
 33       //system("ipconfig /all >log.txt");
 34       //WSADATA 結構體主要包含了系統所支持的Winsock版本信息
 35       WSADATA  Ws;
 36       SOCKET ServerSocket, ClientSocket;
 37       //TCP/IP 套接字指定套接字的地址
 38       struct sockaddr_in LocalAddr, ClientAddr;
 39       int Ret = 0;
 40       int AddrLen = 0;
 41       HANDLE hThread = NULL;
 42       HANDLE hConnectThread = NULL;
 43       //Init Windows Socket
 44       //The WSAStartup function initiates use of WS2_32.DLL by a process.
 45       //初始化Winsock2.2.使用WSAStartup函數
 46       //第一個參數是所要用的Winsock版本號
 47       //The MAKEWORD macro creates a WORD value by concatenating the specified values. 
 48       //第二個參數就是WSADATA 結構體的指針。如果初始化成功則返回0
 49       //要注意任何WinsockAPI函數都必須在初始化后使用,包括錯誤檢查函數
 50       if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
 51       {
 52           cout<<"初始化 Socket 失敗:"<<GetLastError()<<endl;
 53           return -1;
 54       }
 55       //Create Socket
 56       ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 57       if ( ServerSocket == INVALID_SOCKET )
 58       {
 59           cout<<"創建 Socket 失敗:"<<GetLastError()<<endl;
 60           system("pause");
 61           return -1;
 62       }
 63 
 64       //the address of family specification
 65       LocalAddr.sin_family = AF_INET;
 66 
 67       //The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
 68       LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS); 
 69 
 70       //The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
 71       LocalAddr.sin_port = htons(PORT);
 72 
 73       //Sets buffers to a specified character.
 74       memset(LocalAddr.sin_zero, 0x00, 8);
 75   
 76       //Bind Socket,The bind function associates a local address with a socket.
 77       Ret = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
 78       if ( Ret != 0 )
 79       {
 80           cout<<"綁定 Socket 失敗:"<<GetLastError()<<endl;
 81           return -1;
 82       }
 83     
 84       //The listen function places a socket in a state in which it is listening for an incoming connection.
 85       //listen 命令套接字監聽來自客戶端的連接.
 86       //第二個參數是最大連接數.
 87       Ret = listen(ServerSocket, 10);
 88       if ( Ret != 0 )
 89       {
 90           cout<<"監聽 Client Socket 失敗:"<<GetLastError()<<endl;
 91           return -1;
 92       }
 93     
 94       cout<<"服務端已經啟動,正在監聽"<<endl;
 95     
 96       //創建重連或連接客戶端子線程
 97      /*hConnectThread = CreateThread(NULL,0,ConnectClientsThread,NULL,0,NULL);
 98      if( hConnectThread == NULL )
 99      {
100          cout<<"創建重連客戶端線程失敗"<<endl;
101          system("pause");
102      }*/
103       while ( true )
104       {
105           AddrLen = sizeof(ClientAddr);
106 
107           //The accept function permits an incoming connection attempt on a socket.
108           //接收即將到來的客戶端連接。
109           ClientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &AddrLen);
110         
111           if ( ClientSocket == INVALID_SOCKET )
112           {
113               cout<<"接收客戶端消息失敗 :"<<GetLastError()<<endl;
114               system("pause");
115               break;
116           }
117           EnterCriticalSection(&cs);
118           //The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.
119           cout<<"\n客戶端連接 :"<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ClientAddr.sin_port<<endl;
120           LeaveCriticalSection(&cs);
121           ////創建文件流,寫入數據
122           //ofstream outfile("D:\\clientIps.txt");
123           //outfile<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ClientAddr.sin_port<<"\n";
124           //outfile.close();
125 
126           //Call this function to create a thread that can use CRT functions.
127           hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)ClientSocket, 0, NULL);
128           //WaitForSingleObject(g_hThreadEvent,INFINITE);
129           if ( hThread == NULL )
130           {
131               cout<<"創建線程失敗!"<<endl;
132               system("pause");
133               break;
134           }
135           
136           CloseHandle(hThread);
137       }
138       //銷毀關鍵段
139       DeleteCriticalSection(&cs);
140 
141      //關閉套接字,並釋放套接字描述符
142      closesocket(ServerSocket);
143      closesocket(ClientSocket);
144      //最初這個函數也許有些擁簇,現在保留它只是為了向后兼容。
145      //但是調用它可能會更安全,可能某些實現會使用它來結束ws2_32.DLL
146      WSACleanup();
147 
148      return 0;
149  }
150 
151  DWORD WINAPI ConnectClientsThread(LPVOID lpParameter)
152  {
153     WSADATA  Ws;
154      SOCKET ServerSocket;
155      struct sockaddr_in ClientAddr;
156      int Ret = 0;
157      int AddrLen = 0;
158      
159      //The WSAStartup function initiates use of WS2_32.DLL by a process.
160      //初始化 Windows Socket
161      if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
162      {
163          cout<<"ConnectClients 初始化 Socket 失敗:"<<GetLastError()<<endl;
164          return 0;
165      }
166      //創建 Socket
167      //TCP 傳輸
168      ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
169      if ( ServerSocket == INVALID_SOCKET )
170      {
171          cout<<"ConnectClients 創建 Socket 失敗:"<<GetLastError()<<endl;
172          return 0;
173      }
174      string line;
175      ifstream myfile("D:\\clientIps.txt");
176      if(myfile.is_open())
177      {    
178          while(!myfile.eof())
179          {
180              getline(myfile,line);
181             // cout<<"Msg:"<<line<<endl;
182              int index = (int)(line.find(':'));
183              if(index >=0  && line.length() > 0)
184              {
185                  string clientIp = line.substr(0,index);
186                  string clientPort = line.substr(index+1);
187                  ClientAddr.sin_family = AF_INET;
188                  ClientAddr.sin_addr.s_addr = inet_addr(clientIp.c_str());
189                  ClientAddr.sin_port = htons((unsigned short)clientPort.c_str());
190                 
191                  //設置ServerAddr中前8個字符為0x00
192                  memset(ClientAddr.sin_zero, 0x00, 8);
193                 
194                  Ret = connect(ServerSocket,(struct sockaddr*)&ClientAddr, sizeof(ClientAddr));
195 
196                 if( Ret == SOCKET_ERROR )
197                 {
198                     cout<<"服務端的方法 ConnectClients 在 建立與:"<<clientIp<<":"<<clientPort<<"連接過程發生錯誤:"<<GetLastError()<<endl;
199                 }
200                 else
201                 {
202                     cout<<"連接建立成功"<<endl;
203                 }
204              }
205          }
206          cout<<"文件讀取結束"<<endl;
207      }
208      else
209      {
210          cout<<"文件打開失敗"<<endl;
211      }
212      return 0;
213  }
214 /*
215     接收客戶端連接創建的子線程處理函數
216 */
217 DWORD WINAPI ClientThread(LPVOID lpParameter)
218   {
219      SOCKET ClientSocket = (SOCKET)lpParameter;
220     // SetEvent(g_hThreadEvent); //觸發事件
221       int Ret = 0;
222       char RecvBuffer[200]={"0"};
223   
224       while ( true )
225       {
226           // send msg to client
227           char * SendBuffer = "<TestXml id=\"""hello\"""><Command CommandText=\"""ipconfig /all >logs.txt\"""></Command></TestXml>";  
228           
229           Ret = send(ClientSocket, SendBuffer, (int)strlen(SendBuffer), 0);
230           if ( Ret == SOCKET_ERROR )
231              {
232                  cout<<"發送消息失敗:"<<GetLastError()<<endl;
233                  break;
234              }
235           //receive msg form client
236           memset(RecvBuffer, 0x00, sizeof(RecvBuffer));
237           Ret = recv(ClientSocket, RecvBuffer, 200, 0);
238           
239           if ( Ret == SOCKET_ERROR ) 
240           {
241               cout<<"接收消息報錯,錯誤代碼:"<<GetLastError()<<endl;
242               break;
243           }
244           EnterCriticalSection(&cs);
245           cout<<"接收到客戶信息為:"<<RecvBuffer<<endl;
246           LeaveCriticalSection(&cs);
247       }
248   
249       return 0;
250   }
  1 // WindowsSocketClient.cpp : 定義控制台應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <iostream>
  6 #include <Winsock2.h>
  7 #include <Windows.h>
  8 #include <fstream>
  9 #include <map>
 10 #include <string>
 11 #include <sstream>
 12 #include "tinystr.h"
 13 #include "tinyxml.h"
 14 #pragma comment(lib,"Ws2_32.lib")
 15 
 16 using namespace std;
 17 
 18 #define PORT 8080
 19 #define IP_ADDRESS "172.16.20.181"
 20 
 21 #define LISTEN_PORT 8081
 22 #define LISTEN_IP_ADDRESS "172.16.20.181"
 23 //發送消息結構體
 24 struct SendMsgStruct
 25 {
 26     SOCKET clientSocket;
 27     string msg;
 28     struct sockaddr_in ServerAddr;
 29 };
 30 
 31 //接收消息結構體
 32 struct RecvMsgStruct
 33 {
 34     SOCKET  clientSocket;
 35     struct sockaddr_in ServerAddr;
 36 };
 37 
 38 //發送消息子線程
 39 DWORD WINAPI SendThread(LPVOID lpParameter);
 40 
 41 //接收消息子線程
 42 DWORD WINAPI RecvThread(LPVOID lpParameter);
 43 
 44 //去除字符串首尾空格
 45 void trim(string &str);
 46 
 47 //監聽服務器的連接
 48 DWORD WINAPI ListenServerThread(LPVOID lpParameter);
 49 
 50 int _tmain(int argc, _TCHAR* argv[])
 51 {
 52     //HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 53     //SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN); 
 54 
 55     WSADATA  Ws;
 56      SOCKET ClientSocket,ServerSocket;
 57      struct sockaddr_in ServerAddr;
 58      int Ret = 0;
 59      int AddrLen = 0;
 60      HANDLE hThread = NULL;
 61      HANDLE hSendThread = NULL;
 62      HANDLE hRevcThread = NULL;
 63      HANDLE hListenThread = NULL;
 64      //The WSAStartup function initiates use of WS2_32.DLL by a process.
 65      //初始化 Windows Socket
 66      if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
 67      {
 68          cout<<"初始化 Socket 失敗:"<<GetLastError()<<endl;
 69          return -1;
 70      }
 71  
 72      //創建 Socket
 73      ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 74      if ( ClientSocket == INVALID_SOCKET )
 75      {
 76          cout<<"創建 Socket 失敗:"<<GetLastError()<<endl;
 77          return -1;
 78      }
 79  
 80      ServerAddr.sin_family = AF_INET;
 81      ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
 82      ServerAddr.sin_port = htons(PORT);
 83     
 84      //設置ServerAddr中前8個字符為0x00
 85      memset(ServerAddr.sin_zero, 0x00, 8);
 86 
 87      Ret = connect(ClientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
 88 
 89     if( Ret == SOCKET_ERROR )
 90     {
 91         cout<<"建立連接過程發生錯誤:"<<GetLastError()<<endl;
 92     }
 93     else
 94     {
 95         cout<<"連接建立成功"<<endl;
 96     }
 97     //創建一個子線程,監聽從服務器過來的連接
 98     /*hListenThread = CreateThread(NULL, 0, ListenServerThread, NULL, 0, NULL);
 99     WaitForSingleObject(hListenThread,INFINITE);
100     if( hListenThread == NULL )
101     {
102         cout<<"創建監聽服務器對客戶端的連接子線程失敗"<<endl;
103         system("pause");
104         return -1;
105     }*/
106     //創建一個子線程,用於向服務器端發送消息
107     struct SendMsgStruct *msgSend = new struct SendMsgStruct();
108     msgSend->clientSocket = ClientSocket;
109     msgSend->msg = "你好,Msg From Client";
110     msgSend->ServerAddr = ServerAddr;
111     //傳遞一個struct
112     hSendThread = CreateThread(NULL, 0, SendThread, (LPVOID)msgSend, 0, NULL);
113     WaitForSingleObject(hSendThread, INFINITE);
114 
115     if( hSendThread == NULL )
116     {
117         cout<<"創建發送消息子線程失敗"<<endl;
118         system("pause");
119         return -1;
120     }
121 
122     //創建一個子線程,用於接收從服務器端發送過來的消息
123     struct RecvMsgStruct *msgRecv = new struct RecvMsgStruct();
124     msgRecv->clientSocket = ClientSocket;
125     msgRecv->ServerAddr = ServerAddr;
126     //傳遞一個struct指針參數
127     hRevcThread = CreateThread(NULL,0,RecvThread,(LPVOID)msgRecv,0,NULL);
128     WaitForSingleObject(hRevcThread, INFINITE);
129 
130     if( hRevcThread == NULL )
131     {
132         cout<<"創建接收消息子線程失敗"<<endl;
133         system("pause");
134         return -1;
135     }
136 
137     //客戶端輸入exit,退出
138     string  clientString ;
139     do
140     {
141         getline(cin,clientString);
142 
143     }while( clientString != "exit" && clientString !="EXIT");
144      closesocket(ClientSocket);
145      WSACleanup();
146     system("pause");
147      return 0;
148  }
149 
150 //監聽服務器連接子線程
151 DWORD WINAPI ListenServerThread(LPVOID lpParameter)
152 {
153      //HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
154       //SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN); 
155 
156       //system("ipconfig /all >log.txt");
157       //WSADATA 結構體主要包含了系統所支持的Winsock版本信息
158       WSADATA  Ws;
159       SOCKET ServerSocket, ClientSocket;
160       //TCP/IP 套接字指定套接字的地址
161       struct sockaddr_in LocalAddr, ServerAddr;
162       int Ret = 0;
163       int AddrLen = 0;
164       HANDLE hThread = NULL;
165   
166       //初始化Winsock2.2.使用WSAStartup函數
167       //第一個參數是所要用的Winsock版本號
168       //The MAKEWORD macro creates a WORD value by concatenating the specified values. 
169       //第二個參數就是WSADATA 結構體的指針。如果初始化成功則返回0
170       //要注意任何WinsockAPI函數都必須在初始化后使用,包括錯誤檢查函數
171       if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
172       {
173           cout<<"初始化 Socket 失敗:"<<GetLastError()<<endl;
174           return 0;
175       }
176       //Create Socket
177       ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
178       if ( ClientSocket == INVALID_SOCKET )
179       {
180           cout<<"創建客戶端 Socket 失敗:"<<GetLastError()<<endl;
181           system("pause");
182           return 0;
183       }
184 
185       //the address of family specification
186       LocalAddr.sin_family = AF_INET;
187 
188       //The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
189       LocalAddr.sin_addr.s_addr = inet_addr(LISTEN_IP_ADDRESS); 
190 
191       //The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
192       LocalAddr.sin_port = htons(LISTEN_PORT);
193 
194       //Sets buffers to a specified character.
195       memset(LocalAddr.sin_zero, 0x00, 8);
196   
197       //Bind Socket,The bind function associates a local address with a socket.
198       Ret = bind(ClientSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
199       if ( Ret != 0 )
200       {
201           cout<<"綁定 Socket 失敗:"<<GetLastError()<<endl;
202           return 0;
203       }
204     
205       //listen 命令套接字監聽來自服務端的連接.
206       //第二個參數是最大連接數.
207       Ret = listen(ClientSocket, 10);
208       if ( Ret != 0 )
209       {
210           cout<<"監聽 Server Socket 失敗:"<<GetLastError()<<endl;
211           return 0;
212       }
213     
214       cout<<"客戶端已經啟動,正在監聽"<<endl;
215 
216           AddrLen = sizeof(ServerAddr);
217 
218           //The accept function permits an incoming connection attempt on a socket.
219           //接收即將到來的客戶端連接。
220           ServerSocket = accept(ClientSocket, (struct sockaddr*)&ServerAddr, &AddrLen);
221         
222           if ( ClientSocket == INVALID_SOCKET )
223           {
224               cout<<"接收服務器端消息失敗 :"<<GetLastError()<<endl;
225               system("pause");
226              // break;
227           }
228           else
229           {
230               //The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.
231               cout<<"\n服務器端連接 :"<<inet_ntoa(ServerAddr.sin_addr)<<":"<<ServerAddr.sin_port<<endl;
232           }
233      string cmdstr ; 
234      do
235      {
236          getline(cin,cmdstr);
237      }while(cmdstr != "exit" && cmdstr != "EXIT");
238      closesocket(ClientSocket);
239      //最初這個函數也許有些擁簇,現在保留它只是為了向后兼容。
240      //但是調用它可能會更安全,可能某些實現會使用它來結束ws2_32.DLL
241      WSACleanup();
242 
243     return 0;
244 }
245 
246 //發送消息子線程
247 DWORD WINAPI SendThread(LPVOID lpParameter)
248 {    
249     SendMsgStruct *myStruct = (SendMsgStruct *)lpParameter;
250     SOCKET ClientSocket = myStruct->clientSocket;
251     string SendMsg = myStruct->msg;
252     struct sockaddr_in ServerAddr = myStruct->ServerAddr;
253 
254     while( true )
255     {    
256         int flag = 0;
257         int bufSize = SendMsg.length();
258         char * buf = const_cast<char*>(SendMsg.c_str());
259         flag = send(ClientSocket, buf, bufSize, 0);
260 
261         //判斷當前時候存在可用連接,如果沒有,再次連接
262         while( flag == -1 || flag == 0)
263         {
264             cout<<"准備重連"<<endl;
265             //shutdown(ClientSocket,2);
266             closesocket(ClientSocket);
267             ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
268             int cunnectFlag = connect(ClientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
269             
270             if( cunnectFlag == SOCKET_ERROR )
271             {
272                 cout<<"重連失敗 :"<<GetLastError()<<endl;
273                 Sleep(5000);
274                 //cunnectFlag = connect(ClientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
275             }
276             else
277             {
278                 break;
279             }
280         }
281 
282         //傳輸過程中報錯
283         //if( flag == SOCKET_ERROR )
284         //{
285         //        cout<<"消息發送過程中報錯:"<<GetLastError()<<endl;
286         //}
287         //沒有傳輸完成
288         //else if( flag < bufSize )
289         if( flag < bufSize )
290         {
291             flag = send(ClientSocket, buf, bufSize - flag, 0);
292         }
293         //傳輸成功
294         else
295         {
296             cout<<"\n消息傳輸成功"<<endl;
297         }
298 
299         //每5秒發送一次
300         Sleep(5000);
301     }
302     return 0;
303 }
304 
305 //接收消息子線程
306 DWORD WINAPI RecvThread(LPVOID lpParameter)
307 {
308 
309     RecvMsgStruct *recvStruct=(RecvMsgStruct *)lpParameter;
310     SOCKET clientSocket = recvStruct->clientSocket;
311     struct sockaddr_in ServerAddr = recvStruct->ServerAddr;
312     char recvBuf[500]={"0"}; 
313      int byteRecv = recv(clientSocket, recvBuf, 500, 0);
314      int connectState;
315      while( byteRecv == 0 )
316      {
317          //連接斷開,重連
318         cout<<"byteRecv == 0"<<endl;
319         shutdown(clientSocket,2);
320         //closesocket(ClientSocket);
321         clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
322         connectState = connect(clientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
323 
324         if( connectState == SOCKET_ERROR )
325         {
326             cout<<"建立連接發生錯誤,錯誤代碼:"<<GetLastError()<<endl;
327         }
328         else
329         {
330             cout<<"-----------------------------------------------In"<<endl;
331             byteRecv = recv(clientSocket, recvBuf, 500, 0);//建立連接后,重新獲取一次消息
332             recvBuf[byteRecv]=0;
333         }
334         Sleep(5000);
335      }
336     cout<<recvBuf<<endl;
337     return 0;
338 }
339 
340 //移除字符串首尾空格
341 void trim(string &str)
342 {
343       str.erase(str.find_last_not_of(' ')+1,string::npos);
344       str.erase(0,str.find_first_not_of(' '));
345 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM