這篇文章主要介紹了C++中SOCKET多線程怎么實(shí)現(xiàn)聊天小程序的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇C++中SOCKET多線程怎么實(shí)現(xiàn)聊天小程序文章都會(huì)有所收獲,下面我們一起來看看吧。
創(chuàng)新互聯(lián)公司是一家以網(wǎng)站建設(shè)公司、網(wǎng)頁設(shè)計(jì)、品牌設(shè)計(jì)、軟件運(yùn)維、seo優(yōu)化排名、小程序App開發(fā)等移動(dòng)開發(fā)為一體互聯(lián)網(wǎng)公司。已累計(jì)為成都木屋等眾行業(yè)中小客戶提供優(yōu)質(zhì)的互聯(lián)網(wǎng)建站和軟件開發(fā)服務(wù)。
什么是網(wǎng)絡(luò)協(xié)議?
計(jì)算機(jī)網(wǎng)絡(luò)中,各個(gè)實(shí)體之間的數(shù)據(jù)交換必須遵守事先約定好的規(guī)則,這些規(guī)則就稱為協(xié)議。
網(wǎng)絡(luò)協(xié)議的組成要素有:
1.語法,數(shù)據(jù)與控制信息的結(jié)構(gòu)或格式
2.語義:需要發(fā)出何種控制信息,完成哪些動(dòng)作以及做出何種響應(yīng)
3.時(shí)序:事件實(shí)現(xiàn)順序的詳細(xì)說明
在一個(gè)網(wǎng)絡(luò)協(xié)議中,通信的實(shí)體的相同層次的結(jié)構(gòu)必須執(zhí)行相同的協(xié)議,這是協(xié)議的對(duì)等性原則。
TCP/IP體系結(jié)構(gòu)與SOCKET
關(guān)于TCP/IP體系結(jié)構(gòu)的詳細(xì)內(nèi)容本文不做論述,如果你沒有這方面的知識(shí)想要快速理解這個(gè)東西,可以把網(wǎng)絡(luò)通信類比成兩個(gè)人之間寫信。你的信件就是通信過程中要傳遞的消息或者數(shù)據(jù),而網(wǎng)絡(luò)協(xié)議對(duì)你的“信件”進(jìn)行了包裝,比如給你貼了郵票、包了信封、投進(jìn)了郵箱,然后你的“信件”就能通過郵局送到收信人那里。
SOCKET(套接字)是TCP/IP網(wǎng)絡(luò)操作系統(tǒng)為網(wǎng)絡(luò)程序開發(fā)提供的典型網(wǎng)絡(luò)編程界面,進(jìn)程通過SOCKET發(fā)送消息和接收消息。你可以把SOCKET看作一道“門”,發(fā)送消息的進(jìn)程從“門”把消息推出去;消息被推出之后利用下層的通信設(shè)施傳遞到接收進(jìn)程所在的“門”;然后接收進(jìn)程再從“門”把消息拉進(jìn)去。套接字SOCKET又分為數(shù)據(jù)報(bào)套接字和流式套接字,分別使用UDP協(xié)議和TCP協(xié)議。
SOCKET編程
我們嘗試編寫一個(gè)單播聊天室,這個(gè)聊天室可以讓多個(gè)客戶端與服務(wù)器端進(jìn)行連接,而單播的意思是各個(gè)客戶端只能與服務(wù)端進(jìn)行單獨(dú)通信,不同客戶端之間無法通信。為了實(shí)現(xiàn)這個(gè)目標(biāo)我們還需要用到多線程。整體實(shí)現(xiàn)思路如下圖:
話不多說,上代碼。
Server端
#include "stdafx.h" #include<WinSock2.h> #include<string.h> #include<iostream> #pragma comment (lib, "ws2_32.lib") using namespace std; const int PORT = 8000; #define IP "127.0.0.1" #define MaxClient 10//最多能接受同時(shí)在線的客戶端數(shù)量,可以隨意修改 #define MaxBufSize 1024 int num =0;//客戶端數(shù)量計(jì)數(shù)器 #define _CRT_SECURE_NO_WARINGS //服務(wù)線程 DWORD WINAPI SeverThread(LPVOID lpParameter) { //新建一個(gè)SOCKET用于通信 SOCKET *ClientSocket = (SOCKET*)lpParameter; int receByt = 0; char RecvBuf[MaxBufSize]; char SendBuf[MaxBufSize]; char exitBuf[5]; //開始接收 while (1) { receByt = recv(*ClientSocket, RecvBuf, sizeof(RecvBuf), 0); if (receByt > 0) { //當(dāng)客戶端發(fā)來的消息是“exit”,就關(guān)閉連接 if (strlen(RecvBuf)==4) { for (int i = 0; i < 5; i++) { exitBuf[i] = RecvBuf[i]; } int flag = strcmp(exitBuf, "exit"); if (flag==0)//接收到exit消息 { cout << "client " << *ClientSocket << " exit!" << endl; num--; send(*ClientSocket, "Your server has been closed", sizeof(SendBuf), 0); closesocket(*ClientSocket); return 0; } } cout << "receive message :" << RecvBuf << " from client:" << *ClientSocket << endl; } else { //下面說到的客戶端關(guān)閉連接是指客戶端掉線了 if (WSAGetLastError() == 10054)//檢測到客戶端關(guān)閉連接 { cout << "client " << *ClientSocket << " exit!" << endl; closesocket(*ClientSocket); num--; return 0; } else//接收失敗顯示錯(cuò)誤信息 { cout << "failed to receive,Error:" << WSAGetLastError() << endl; break; } } memset(RecvBuf, 0, 1024); cout << "input your message to client:" << endl; scanf_s("%s",SendBuf,MaxBufSize); int k = 0; k = send(*ClientSocket, SendBuf, sizeof(SendBuf), 0); if (k < 0) { if (WSAGetLastError()==10054)//檢測到客戶端主動(dòng)關(guān)閉連接 { cout << "client " << *ClientSocket << " exit!" << endl; closesocket(*ClientSocket); num--; return 0; } else//發(fā)送失敗顯示錯(cuò)誤信息 cout << "failed to send, Error:" << WSAGetLastError()<<endl; } memset(SendBuf, 0, 1024); } if (*ClientSocket != INVALID_SOCKET) { closesocket(*ClientSocket); } return 0; } int _tmain(int argc, _TCHAR* argv[]) { WSAData wsd; WSAStartup(MAKEWORD(2, 2), &wsd); SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN ListenAddr; ListenAddr.sin_family = AF_INET; ListenAddr.sin_addr.S_un.S_addr = INADDR_ANY;//本機(jī)ip ListenAddr.sin_port = htons(PORT); //綁定監(jiān)聽端口 int n; n = bind(ListenSocket, (LPSOCKADDR)&ListenAddr, sizeof(ListenAddr)); if (n == SOCKET_ERROR) { cout << "failed to bind!" << endl; return -1; } else { cout << "bind success to:" << PORT << endl; } //開始監(jiān)聽 int l = listen(ListenSocket, MaxClient); if (l == 0) { cout << "server ready, wait to requirement..." << endl; } else { cout << "Error:" << GetLastError() << "listen return" << l << endl; } while (1) { //循環(huán)接收客戶端連接請(qǐng)求并創(chuàng)建服務(wù)線程 if(num < MaxClient) { SOCKET *ClientSocket=new SOCKET; HANDLE hThread; int SockAddrlen = sizeof(sockaddr); *ClientSocket = accept(ListenSocket, 0, 0); cout << "client " << *ClientSocket << " has connect to server" << endl; num++; hThread = CreateThread(NULL, NULL, &SeverThread, (LPVOID)ClientSocket, 0, NULL); CloseHandle(hThread); } else { cout << "Max Client!Please wait for accept..." << endl; } } closesocket(ListenSocket); WSACleanup(); return 0; }
在這個(gè)服務(wù)器端,每有一個(gè)新的客戶端請(qǐng)求建立連接,服務(wù)器都會(huì)新開一個(gè)線程為一個(gè)客戶端提供服務(wù),并在這個(gè)線程中新建立一個(gè)SOCKET用于與客戶端進(jìn)行通信,同時(shí)服務(wù)器也應(yīng)該能夠在不同階段(接收或發(fā)送)檢測客戶端是否已經(jīng)斷開連接,以便及時(shí)釋放資源。
Client端
#include "stdafx.h" #include<iostream> #include<cstdio> #include<string> #include<Winsock2.h> #pragma comment(lib,"ws2_32.lib") using namespace std; const int PORT = 8000; #define MaxBufSize 1024 #define _CRT_SECURE_NO_WARINGS int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsd; WSAStartup(MAKEWORD(2, 2), &wsd); SOCKET SocketClient = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN ClientAddr; ClientAddr.sin_family = AF_INET; ClientAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); ClientAddr.sin_port = htons(PORT); int n = 0; n = connect(SocketClient, (struct sockaddr*)&ClientAddr, sizeof(ClientAddr)); if (n == SOCKET_ERROR) { cout << "failed to connect" << endl; return -1; } cout << "success to connect to Server" << endl; char info[1024];//數(shù)據(jù)輸入緩沖區(qū) char SendBuff[MaxBufSize];//發(fā)送數(shù)據(jù)緩沖區(qū) char RecvBuff[MaxBufSize];//接收數(shù)據(jù)緩沖區(qū) while (1) { cout << "input your message:" << endl; scanf_s("%s",&info,MaxBufSize); if (info[0] == '\0') break; strcpy(SendBuff, info); memset(info, 0, sizeof(info)); int k = 0; k = send(SocketClient, SendBuff, sizeof(SendBuff), 0); memset(SendBuff, 0, sizeof(SendBuff)); if (k < 0) { cout << WSAGetLastError() << endl; cout << "failed to send" << endl; } int n = 0; n = recv(SocketClient, RecvBuff, sizeof(RecvBuff), 0); if (n>0) { cout << "receive message from Server:" << RecvBuff << endl; memset(RecvBuff, 0, sizeof(RecvBuff)); } } closesocket(SocketClient); WSACleanup(); return 0; }
在本例中,客戶端與服務(wù)器建立連接后,必須由客戶端先發(fā)送消息才能開啟對(duì)話。支持中英文聊天,一次最多發(fā)送1024個(gè)字節(jié)的數(shù)據(jù)。你要建立多個(gè)客戶端的話只需要再新建幾個(gè)工程然后把Client的代碼復(fù)制進(jìn)去運(yùn)行即可?;蛘咧苯佣鄰?fù)制幾個(gè)編譯生成的exe程序。
關(guān)于“C++中SOCKET多線程怎么實(shí)現(xiàn)聊天小程序”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“C++中SOCKET多線程怎么實(shí)現(xiàn)聊天小程序”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
本文名稱:C++中SOCKET多線程怎么實(shí)現(xiàn)聊天小程序
文章URL:http://bm7419.com/article14/pcgpde.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、動(dòng)態(tài)網(wǎng)站、網(wǎng)站建設(shè)、商城網(wǎng)站、App設(shè)計(jì)、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)