通訊建立后首先由服務(wù)器端發(fā)送消息,客戶端接收消息;接著客戶端發(fā)送消息,服務(wù)器端接收消息,實現(xiàn)交互發(fā)送消息。
服務(wù)器同時可以和多個客戶端建立連接,進行交互;
在某次交互中,服務(wù)器端或某客戶端有一方發(fā)送"end"即終止服務(wù)器與其的通信;服務(wù)器還可以繼續(xù)接收其他客戶端的請求,與其他客戶端通信。
服務(wù)器端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#include <WinSock2.h> #include <WS2tcpip.h> #include <iostream> using namespace std; #pragma comment(lib, "ws2_32.lib") #define PORT 65432 DWORD WINAPI ThreadFun( LPVOID lpThreadParameter); int main() { //初始化winsock2.DLL WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) { cout << "加載winsock.dll失敗!" << endl; return 0; } //創(chuàng)建套接字 SOCKET sock_server; if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { cout << "創(chuàng)建套接字失敗!錯誤代碼:" << WSAGetLastError() << endl; WSACleanup(); return 0; } //綁定端口和Ip sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(PORT); inet_pton(AF_INET, "127.0.0.1" , &addr.sin_addr); //綁定本機的環(huán)回地址 if (SOCKET_ERROR == bind(sock_server, (SOCKADDR*)&addr, sizeof (sockaddr_in))) { cout << "地址綁定失敗!錯誤代碼:" << WSAGetLastError() << endl; closesocket(sock_server); WSACleanup(); return 0; } //將套接字設(shè)為監(jiān)聽狀態(tài) listen(sock_server, 0); //主線程循環(huán)接收客戶端的連接 while (1) { sockaddr_in addrClient; int len = sizeof (sockaddr_in); //接收成功返回與client通訊的socket SOCKET con = accept(sock_server, (SOCKADDR*)&addrClient, &len); if (con != INVALID_SOCKET) { //創(chuàng)建線程 并且傳入與client通訊的套接字 HANDLE hThread = CreateThread(NULL, 0, ThreadFun, ( LPVOID )con, 0, NULL); CloseHandle(hThread); //關(guān)閉對線程的引用 } } closesocket(sock_server); WSACleanup(); return 0; } //線程通訊部分 DWORD WINAPI ThreadFun( LPVOID lpThreadParameter) { //與客戶端通訊 先發(fā)送再接收數(shù)據(jù) SOCKET sock = (SOCKET)lpThreadParameter; cout << "成功和" << sock << "建立連接!" << endl; while (1) { char msgbuffer[1000]; //字符緩沖區(qū) printf ( "服務(wù)器向%d發(fā)送數(shù)據(jù):\n" , sock); cin.getline(msgbuffer, sizeof (msgbuffer)); int size = send(sock, msgbuffer, sizeof (msgbuffer), 0); //給客戶端發(fā)送一段信息 if ( strcmp (msgbuffer, "end\0" ) == 0) { cout << "關(guān)閉和" << sock << "的連接!" << endl; return 0; } if (size == SOCKET_ERROR || size == 0) { cout << "發(fā)送信息失敗!錯誤代碼:" << WSAGetLastError() << endl; return 0; } else cout << "信息發(fā)送成功!" << endl; //接收客戶端數(shù)據(jù) msgbuffer[999] = { 0 }; int ret = recv(sock, msgbuffer, sizeof (msgbuffer), 0); if (ret == SOCKET_ERROR || ret == 0) { cout << sock << "斷開了連接!" << endl; break ; } else cout << sock << " 說: " << msgbuffer << endl; } return 0; } |
客戶端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
#include <winsock2.h> #include <WS2tcpip.h> #include <iostream> using namespace std; #pragma comment(lib, "ws2_32.lib") #define PORT 65432 int main() { //初始化winsock2.DLL WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) { cout << "加載winsock.dll失敗!" << endl; return 0; } //創(chuàng)建套接字 SOCKET sock_client; if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { cout << "創(chuàng)建套接字失敗!錯誤代碼:" << WSAGetLastError() << endl; WSACleanup(); return 0; } //連接服務(wù)器 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(PORT); inet_pton(AF_INET, "127.0.0.1" , &addr.sin_addr); //綁定本機的環(huán)回地址 int len = sizeof (sockaddr_in); if (connect(sock_client, (SOCKADDR*)&addr, len) == SOCKET_ERROR) { cout << "連接失敗!錯誤代碼:" << WSAGetLastError() << endl; return 0; } //實現(xiàn)交互部分,客戶端先接收后發(fā)送數(shù)據(jù) while (1) { //接收服務(wù)端的消息 char msgbuffer[1000] = { 0 }; int size = recv(sock_client, msgbuffer, sizeof (msgbuffer), 0); if ( strcmp (msgbuffer, "end\0" ) == 0) { cout << "服務(wù)器端已經(jīng)關(guān)閉連接!" << endl; break ; } if (size < 0) { cout << "接收信息失敗!錯誤代碼:" << WSAGetLastError() << endl; break ; } else if (size == 0) { cout << "對方已經(jīng)關(guān)閉連接" << endl; break ; } else cout << "The message from Server:" << msgbuffer << endl; //從鍵盤輸入一行文字發(fā)送給服務(wù)器 msgbuffer[999] = 0 ; cout << "從鍵盤輸入發(fā)給服務(wù)器的信息:" << endl; cin.getline(msgbuffer, sizeof (msgbuffer)); if ( strcmp (msgbuffer, "end\0" ) == 0) { cout << "關(guān)閉連接!" << endl; break ; } int ret = send(sock_client, msgbuffer, sizeof (msgbuffer), 0); if (ret == SOCKET_ERROR || ret == 0) { cout << "發(fā)送信息失敗!錯誤代碼:" << WSAGetLastError() << endl; break ; } else cout << "信息發(fā)送成功!" << endl; } closesocket(sock_client); WSACleanup(); return 0; } |
我們用建立連接時服務(wù)器端接收的客戶端套接字來唯一標識該客戶端。
服務(wù)器端可以隨時接收客戶端的連接并與其進行交互。
運行實例
實例展示了服務(wù)器端和兩個客戶端通信的運行過程,包括正常交互、交互過程中另一服務(wù)器請求建立連接、服務(wù)器主動斷開連接和客戶端主動斷開連接等過程。
到此這篇關(guān)于C++多線程實現(xiàn)TCP服務(wù)器端同時和多個客戶端通信 的文章就介紹到這了,更多相關(guān)C++ 服務(wù)器端和多個客戶端通信 內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/qq_45929428/article/details/116709789