<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文範例為大家分享了C++ SOCKET多執行緒實現聊天小程式的具體程式碼,供大家參考,具體內容如下
什麼是網路協定?
計算機網路中,各個實體之間的資料交換必須遵守事先約定好的規則,這些規則就稱為協定。
網路協定的組成要素有:
1.語法,資料與控制資訊的結構或格式
2.語意:需要發出何種控制資訊,完成哪些動作以及做出何種響應
3.時序:事件實現順序的詳細說明
在一個網路協定中,通訊的實體的相同層次的結構必須執行相同的協定,這是協定的對等性原則。
TCP/IP體系結構與SOCKET
關於TCP/IP體系結構的詳細內容本文不做論述,如果你沒有這方面的知識想要快速理解這個東西,可以把網路通訊類比成兩個人之間寫信。你的信件就是通訊過程中要傳遞的訊息或者資料,而網路協定對你的「信件」進行了包裝,比如給你貼了郵票、包了信封、投進了郵箱,然後你的「信件」就能通過郵局送到收信人那裡。
SOCKET(通訊端)是TCP/IP網路作業系統為網路程式開發提供的典型網路程式設計介面,程序通過SOCKET傳送訊息和接收訊息。你可以把SOCKET看作一道「門」,傳送訊息的程序從「門」把訊息推出去;訊息被推出之後利用下層的通訊設施傳遞到接收程序所在的「門」;然後接收程序再從「門」把訊息拉進去。通訊端SOCKET又分為資料包通訊端和流式通訊端,分別使用UDP協定和TCP協定。
SOCKET程式設計
我們嘗試編寫一個單播聊天室,這個聊天室可以讓多個使用者端與伺服器端進行連線,而單播的意思是各個使用者端只能與伺服器端進行單獨通訊,不同使用者端之間無法通訊。為了實現這個目標我們還需要用到多執行緒。整體實現思路如下圖:
話不多說,上程式碼。
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//最多能接受同時線上的使用者端數量,可以隨意修改 #define MaxBufSize 1024 int num =0;//使用者端數量計數器 #define _CRT_SECURE_NO_WARINGS //服務執行緒 DWORD WINAPI SeverThread(LPVOID lpParameter) { //新建一個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) { //當用戶端發來的訊息是「exit」,就關閉連線 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 { //下面說到的使用者端關閉連線是指使用者端掉線了 if (WSAGetLastError() == 10054)//檢測到使用者端關閉連線 { cout << "client " << *ClientSocket << " exit!" << endl; closesocket(*ClientSocket); num--; return 0; } else//接收失敗顯示錯誤資訊 { 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)//檢測到使用者端主動關閉連線 { cout << "client " << *ClientSocket << " exit!" << endl; closesocket(*ClientSocket); num--; return 0; } else//傳送失敗顯示錯誤資訊 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;//本機ip ListenAddr.sin_port = htons(PORT); //繫結監聽埠 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; } //開始監聽 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) { //迴圈接收使用者端連線請求並建立服務執行緒 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; }
在這個伺服器端,每有一個新的使用者端請求建立連線,伺服器都會新開一個執行緒為一個使用者端提供服務,並在這個執行緒中新建立一個SOCKET用於與使用者端進行通訊,同時伺服器也應該能夠在不同階段(接收或傳送)檢測使用者端是否已經斷開連線,以便及時釋放資源。
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];//資料輸入緩衝區 char SendBuff[MaxBufSize];//傳送資料緩衝區 char RecvBuff[MaxBufSize];//接收資料緩衝區 while (1) { cout << "input your message:" << endl; scanf_s("%s",&info,MaxBufSize); if (info[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; }
在本例中,使用者端與伺服器建立連線後,必須由使用者端先傳送訊息才能開啟對話。支援中英文聊天,一次最多傳送1024個位元組的資料。你要建立多個使用者端的話只需要再新建幾個工程然後把Client的程式碼複製進去執行即可。或者直接多複製幾個編譯生成的exe程式。
本例中,當同時有多個使用者端建立了連線時,他們可以先傳送訊息,伺服器不一定要立即回覆,而當伺服器接收了來自多個使用者端的訊息然後再進行回覆時,回覆的順序是按照接收順序來的,誰的訊息先送到就先回復誰,我們在伺服器端無法指定我接下來的這條訊息發給誰。這是因為我並沒有使用執行緒池,因此不同執行緒之間無法識別也無法建立連線,而作業系統預設當多個執行緒都在等待回覆時(此時這個執行緒處於掛起狀態),如果沒有特殊規定且資源夠用的話 就要遵循先來後到的順序。想要徹底明白這一部分需要一些作業系統的相關知識。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45