C++?Socket實(shí)現(xiàn)TCP與UDP網(wǎng)絡(luò)編程
前言
socket編程分為TCP和UDP兩個模塊,其中TCP是可靠的、安全的,常用于發(fā)送文件等,而UDP是不可靠的、不安全的,常用作視頻通話等。
如下圖:
頭文件與庫:
#include <WinSock2.h> #pragma comment(lib, "ws2_32.lib")
準(zhǔn)備工作:
創(chuàng)建工程后,首先右鍵工程,選擇屬性
然后選擇 C/C++ - 預(yù)處理器 - 預(yù)處理器定義
將字符串 _WINSOCK_DEPRECATED_NO_WARNINGS 添加到里面去,點(diǎn)擊應(yīng)用即可!
TCP
連接過程圖:
創(chuàng)建tcp服務(wù)器和客戶端都是按照上圖的步驟來操作的!
1). 服務(wù)器
初始化套接字庫
對應(yīng)圖中socket()
WORD wVersion; WSADATA wsaData; int err; // 設(shè)置版本,可以理解為1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 將a左移8位變成高位與b合并起來 // 啟動 err = WSAStartup(wVersion, &wsaData);
創(chuàng)建tcp套接字
對應(yīng)圖中socket()
// AF_INET:ipv4 AF_INET6:ipv6 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
綁定到本機(jī)
對應(yīng)圖中bind()
// 準(zhǔn)備綁定信息 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 設(shè)置綁定網(wǎng)卡 addrSrv.sin_family = AF_INET; // 設(shè)置綁定網(wǎng)絡(luò)模式 addrSrv.sin_port = htons(6000); // 設(shè)置綁定端口 // hton: host to network x86:小端 網(wǎng)絡(luò)傳輸:htons大端 // 綁定到本機(jī) int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
監(jiān)聽
對應(yīng)圖中listen()
// 同時(shí)能接收10個鏈接,主要看參數(shù)二的設(shè)置個數(shù) listen(sockSrv, 10);
接收連接請求,返回針對客戶端的套接字
對應(yīng)圖中accept()
SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);
發(fā)送數(shù)據(jù)
對應(yīng)圖中write()
sprintf_s(sendBuf, "hello client!\n"); int iSend = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
接收數(shù)據(jù)
對應(yīng)圖中read()
recv(sockConn, recvBuf, 100, 0);
關(guān)閉套接字
對應(yīng)圖中close()
closesocket(sockConn);
清理套接字庫
WSACleanup();
具體實(shí)現(xiàn)代碼:
#include <iostream> #include <stdio.h> #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") int main(void) { // 1.初始化套接字庫 WORD wVersion; WSADATA wsaData; int err; // 設(shè)置版本,可以理解為1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 將a左移8位變成高位與b合并起來 // 啟動 err = WSAStartup(wVersion, &wsaData); if (err != 0) { return err; } // 檢查:網(wǎng)絡(luò)低位不等于1 || 網(wǎng)絡(luò)高位不等于1 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { // 清理套接字庫 WSACleanup(); return -1; } // 2.創(chuàng)建tcp套接字 // AF_INET:ipv4 AF_INET6:ipv6 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); // 準(zhǔn)備綁定信息 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 設(shè)置綁定網(wǎng)卡 addrSrv.sin_family = AF_INET; // 設(shè)置綁定網(wǎng)絡(luò)模式 addrSrv.sin_port = htons(6000); // 設(shè)置綁定端口 // hton: host to network x86:小端 網(wǎng)絡(luò)傳輸:htons大端 // 3.綁定到本機(jī) int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)); if (retVal == SOCKET_ERROR) { printf("Failed bind:%d\n", WSAGetLastError()); return -1; } // 4.監(jiān)聽,同時(shí)能接收10個鏈接 if (listen(sockSrv, 10) == SOCKET_ERROR) { printf("Listen failed:%d", WSAGetLastError()); return -1; } std::cout << "Server start at port: 6000" << std::endl; SOCKADDR_IN addrCli; int len = sizeof(SOCKADDR); char recvBuf[100]; char sendBuf[100]; while (1) { // 5.接收連接請求,返回針對客戶端的套接字 SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len); if (sockConn == SOCKET_ERROR) { //printf("Accept failed:%d", WSAGetLastError()); std::cout << "Accept failed: " << WSAGetLastError() << std::endl; break; } //printf("Accept client IP:[%s]\n", inet_ntoa(addrCli.sin_addr)); std::cout << "Accept client IP: " << inet_ntoa(addrCli.sin_addr) << std::endl; // 6.發(fā)送數(shù)據(jù) sprintf_s(sendBuf, "hello client!\n"); int iSend = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0); if (iSend == SOCKET_ERROR) { std::cout << "send failed!\n"; break; } // 7.接收數(shù)據(jù) recv(sockConn, recvBuf, 100, 0); std::cout << recvBuf << std::endl; // 關(guān)閉套接字 closesocket(sockConn); } // 8.關(guān)閉套接字 closesocket(sockSrv); // 9.清理套接字庫 WSACleanup(); return 0; }
2). 客戶端
初始化套接字庫
對應(yīng)圖中socket()
WORD wVersion; WSADATA wsaData; int err; // 可以理解為1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 將a左移8位變成高位與b合并起來 // 啟動 err = WSAStartup(wVersion, &wsaData); // 創(chuàng)建TCP套接字 SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
連接服務(wù)器
對應(yīng)圖中connect()
// 連接服務(wù)器 int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
發(fā)送數(shù)據(jù)到服務(wù)器
對應(yīng)圖中write()
char sendBuf[] = "你好,服務(wù)器,我是客戶端!"; send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);
接收服務(wù)器的數(shù)據(jù)
對應(yīng)圖中read()
char recvBuf[100]; recv(sockCli, recvBuf, sizeof(recvBuf), 0);
關(guān)閉套接字并清除套接字庫
對應(yīng)圖中close()
closesocket(sockCli); WSACleanup();
具體實(shí)現(xiàn)代碼:
#include <iostream> #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") int main(void) { // 1.初始化套接字庫 WORD wVersion; WSADATA wsaData; int err; // 可以理解為1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 將a左移8位變成高位與b合并起來 // 啟動 err = WSAStartup(wVersion, &wsaData); if (err != 0) { return err; } // 檢查:網(wǎng)絡(luò)地位不等于1 || 網(wǎng)絡(luò)高位不等于1 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { // 清理套接字庫 WSACleanup(); return -1; } // 創(chuàng)建TCP套接字 SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服務(wù)器地址 addrSrv.sin_port = htons(6000); // 端口號 addrSrv.sin_family = AF_INET; // 地址類型(ipv4) // 2.連接服務(wù)器 int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)); if (err_log == 0) { printf("連接服務(wù)器成功!\n"); } else { printf("連接服務(wù)器失??!\n"); return -1; } char recvBuf[100]; char sendBuf[] = "你好,服務(wù)器,我是客戶端!"; // 3.發(fā)送數(shù)據(jù)到服務(wù)器 send(sockCli, sendBuf, strlen(sendBuf) + 1, 0); // 4.接收服務(wù)器的數(shù)據(jù) recv(sockCli, recvBuf, sizeof(recvBuf), 0); std::cout << recvBuf << std::endl; // 5.關(guān)閉套接字并清除套接字庫 closesocket(sockCli); WSACleanup(); system("pause"); return 0; }
運(yùn)行效果:
3). TCP聊天小項(xiàng)目
下面是根據(jù)上面的代碼修改的一個聊天小項(xiàng)目(使用到了多線程)
只有一個服務(wù)器,服務(wù)器一直開啟等待客戶端連接;
客戶都安可以開啟多個,且可以一直連續(xù)的與服務(wù)器進(jìn)行發(fā)送接收消息;
服務(wù)器給客戶端發(fā)送數(shù)據(jù),得通過1 - 9來區(qū)分到底給那個客戶端發(fā)送消息,例如給第二個客戶端發(fā)送消息:2你好,客戶端
客戶端那邊接收到的數(shù)據(jù)是:你好,客戶端
服務(wù)器代碼:
#include <iostream> #include <WinSock2.h> #include <stdio.h> #include <Windows.h> #include <process.h> #include <vector> #include <conio.h> #include <string.h> #include <string> #pragma comment(lib, "ws2_32.lib") SOCKET sockSrv; std::vector<SOCKET> vec_sockConn; std::vector<SOCKADDR_IN> vec_sockaddr_in; std::vector<int> vec_sockIndex; // 這個結(jié)構(gòu)體用作線程參數(shù) typedef struct SERVER_CLIENT { SOCKET server; SOCKADDR_IN client; int clientIndex; }SC; // 判斷有沒有斷開連接 bool IsSocketClosed(SOCKET clientSocket) { bool ret = false; HANDLE closeEvent = WSACreateEvent(); WSAEventSelect(clientSocket, closeEvent, FD_CLOSE); DWORD dwRet = WaitForSingleObject(closeEvent, 0); if (dwRet == WSA_WAIT_EVENT_0) ret = true; else if (dwRet == WSA_WAIT_TIMEOUT) ret = false; WSACloseEvent(closeEvent); return ret; } // 接收請求 unsigned int WINAPI ThreadAccept(LPVOID p) { static int i = 0; while (1) { SOCKADDR_IN addrCli; int len = sizeof(SOCKADDR); // 5.接收連接請求,返回針對客戶端的套接字 SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len); if (sockConn == SOCKET_ERROR) { printf("Accept failed:%d", WSAGetLastError()); } // 存儲當(dāng)前服務(wù)器與客戶端 連接綁定的socket vec_sockIndex.emplace_back(i++); vec_sockaddr_in.emplace_back(addrCli); vec_sockConn.emplace_back(sockConn); printf("\033[0;%d;40m客戶端[%d]上線\033[0m\n", 31, i); } return 0; } unsigned int WINAPI _ThreadRecv(LPVOID p) { char recvBuf[100]; memset(recvBuf, 0, 100); SC _sc = *(SC *)p; while (1) { Sleep(20); if (IsSocketClosed(_sc.server) == true) { printf("客戶端 [%d] 斷開連接!\n", _sc.clientIndex + 1); break; } // 接收數(shù)據(jù) recv(_sc.server, recvBuf, 100, 0); if (strlen(recvBuf) == 0) { continue; } printf("接收到客戶端 [%d] 的消息:%s\n", _sc.clientIndex + 1, recvBuf); memset(recvBuf, 0, 100); } return 0; } unsigned int WINAPI ThreadRecv(LPVOID p) { static int index = 0; while (1) { // 還沒有客戶端與服務(wù)器進(jìn)行連接 if (vec_sockConn.size() == 0) { continue; } // 接收線程已經(jīng)開啟和客戶端個數(shù)相等 if (vec_sockConn.size() == index) { continue; } SC sc; sc.server = vec_sockConn.at(index); sc.client = vec_sockaddr_in.at(index); sc.clientIndex = vec_sockIndex.at(index); HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, _ThreadRecv, (void *)&sc, 0, NULL); index++; Sleep(20); } return 0; } int main(void) { // 1.初始化套接字庫 WORD wVersion; WSADATA wsaData; int err; // 設(shè)置版本,可以理解為1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 將a左移8位變成高位與b合并起來 // 啟動 err = WSAStartup(wVersion, &wsaData); if (err != 0) { return err; } // 檢查:網(wǎng)絡(luò)低位不等于1 || 網(wǎng)絡(luò)高位不等于1 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { // 清理套接字庫 WSACleanup(); return -1; } // 2.創(chuàng)建tcp套接字 // AF_INET:ipv4 AF_INET6:ipv6 sockSrv = socket(AF_INET, SOCK_STREAM, 0); // 準(zhǔn)備綁定信息 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 設(shè)置綁定網(wǎng)卡 addrSrv.sin_family = AF_INET; // 設(shè)置綁定網(wǎng)絡(luò)模式 addrSrv.sin_port = htons(6000); // 設(shè)置綁定端口 // hton: host to network x86:小端 網(wǎng)絡(luò)傳輸:htons大端 // 3.綁定到本機(jī) int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)); if (retVal == SOCKET_ERROR) { printf("Failed bind:%d\n", WSAGetLastError()); return -1; } // 4.監(jiān)聽,同時(shí)接收10個鏈接 if (listen(sockSrv, 10) == SOCKET_ERROR) { printf("Listen failed:%d", WSAGetLastError()); return -1; } std::cout << "Server start at port: 6000" << std::endl; // 線程句柄 // 創(chuàng)建線程 HANDLE hThread_1 = (HANDLE)_beginthreadex(NULL, 0, ThreadAccept, NULL, 0, NULL); HANDLE hThread_2 = (HANDLE)_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL); //uiInit(); //editPrint(0, ">"); char sendBuf[100]; while (1) { //printf("請輸入發(fā)送內(nèi)容:"); char c = getchar(); // 輸入發(fā)送給誰 scanf_s("%s", sendBuf, 100); // 輸入發(fā)送的內(nèi)容 if (strlen(sendBuf) == 0) { printf("輸入內(nèi)容為空或者超長!\n"); } // 1 至 9 if (c < '1' || c > '9' || vec_sockConn.size() == 0 || c - '0' >= vec_sockConn.size() + 1) { while ((c = getchar()) != '\n'); // 清空輸入緩沖區(qū) memset(sendBuf, 0, 100); printf("輸入內(nèi)容不符合規(guī)則!\n"); continue; } // 發(fā)送數(shù)據(jù) int index = --c - '0'; // 因?yàn)橄聵?biāo)是從零開始的,所以c要先自減 int iSend = send(vec_sockConn.at(index) , sendBuf, strlen(sendBuf) + 1, 0); if (iSend == SOCKET_ERROR) { std::cout << "send failed!\n"; break; } memset(sendBuf, 0, 100); while ((c = getchar()) != '\n'); // 清空輸入緩沖區(qū) } // 關(guān)閉套接字 std::vector<SOCKET>::iterator it = vec_sockConn.begin(); for (; it != vec_sockConn.end(); it++) { closesocket((SOCKET)(*it)); } WaitForSingleObject(hThread_1, INFINITE); WaitForSingleObject(hThread_2, INFINITE); CloseHandle(hThread_1); CloseHandle(hThread_2); // 7.關(guān)閉套接字 closesocket(sockSrv); // 8.清理套接字庫 WSACleanup(); return 0; }
客戶端:
#include <iostream> #include <WinSock2.h> #include <process.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") SOCKET sockCli; // 判斷有沒有斷開連接 bool IsSocketClosed(SOCKET clientSocket) { bool ret = false; HANDLE closeEvent = WSACreateEvent(); WSAEventSelect(clientSocket, closeEvent, FD_CLOSE); DWORD dwRet = WaitForSingleObject(closeEvent, 0); if (dwRet == WSA_WAIT_EVENT_0) ret = true; else if (dwRet == WSA_WAIT_TIMEOUT) ret = false; WSACloseEvent(closeEvent); return ret; } unsigned int WINAPI ThreadRecv(LPVOID p) { char recvBuf[100]; memset(recvBuf, 0, 100); while (1) { Sleep(20); if (IsSocketClosed(sockCli) == true) { printf("服務(wù)器 斷開連接!\n"); break; } // 接收服務(wù)器的數(shù)據(jù) recv(sockCli, recvBuf, sizeof(recvBuf), 0); if (strlen(recvBuf) == 0) continue; std::cout << recvBuf << std::endl; memset(recvBuf, 0, 100); } return 0; } int main(void) { // 1.初始化套接字庫 WORD wVersion; WSADATA wsaData; int err; // 可以理解為1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 將a左移8位變成高位與b合并起來 // 啟動 err = WSAStartup(wVersion, &wsaData); if (err != 0) { return err; } // 檢查:網(wǎng)絡(luò)地位不等于1 || 網(wǎng)絡(luò)高位不等于1 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { // 清理套接字庫 WSACleanup(); return -1; } // 創(chuàng)建TCP套接字 sockCli = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服務(wù)器地址 addrSrv.sin_port = htons(6000); // 端口號 addrSrv.sin_family = AF_INET; // 地址類型(ipv4) // 連接服務(wù)器 int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)); if (err_log == 0) { printf("連接服務(wù)器成功!\n"); } else { printf("連接服務(wù)器失??!\n"); return -1; } // 線程句柄 // 創(chuàng)建線程 HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL); char sendBuf[100]; while (1) { //printf("請輸入發(fā)送內(nèi)容:"); scanf_s("%s", sendBuf, 100); // 發(fā)送數(shù)據(jù)到服務(wù)器 send(sockCli, sendBuf, strlen(sendBuf) + 1, 0); memset(sendBuf, 0, 100); char c; while ((c = getchar()) != '\n'); } WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); // 關(guān)閉套接字并清除套接字庫 closesocket(sockCli); WSACleanup(); system("pause"); return 0; }
運(yùn)行效果:
UDP
UDP就比較簡單了,步驟比tcp要少一些。
連接過程圖:
1). 服務(wù)器
初始化套接字庫
WORD wVersion; WSADATA wsaData; int err; wVersion = MAKEWORD(1, 1);
創(chuàng)建套接字
SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
綁定
// SOCKADDR_IN addrSrv; 省略了定義和賦值 bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
接收數(shù)據(jù)
char recvBuf[100]; recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);
發(fā)送數(shù)據(jù)
char sendBuf[] = "hello Client,I'm Server!\n"; sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrCli, len);
關(guān)閉
closesocket(sockSrv); WSACleanup();
具體實(shí)現(xiàn)代碼:
#include <WinSock2.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") int main(void) { // 初始化套接字庫 WORD wVersion; WSADATA wsaData; int err; wVersion = MAKEWORD(1, 1); err = WSAStartup(wVersion, &wsaData); if (err != 0) { return err; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return -1; } // 創(chuàng)建套接字 SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6001); // 綁定到本機(jī)6001端口 bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)); // 接收請求,處理請求 SOCKADDR_IN addrCli; int len = sizeof(SOCKADDR); char sendBuf[] = "hello Client,I'm Server!\n"; char recvBuf[100]; std::cout << "start UDP server with port 6001" << std::endl; while (1) { // 接收數(shù)據(jù) recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len); std::cout << "Recv:" << recvBuf << std::endl; // 發(fā)送數(shù)據(jù) sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrCli, len); std::cout << "Send:" << sendBuf << std::endl; } closesocket(sockSrv); WSACleanup(); return 0; }
2). 客戶端
初始化套接字庫
WORD wVersion; WSADATA wsaData; int err; wVersion = MAKEWORD(1, 1);
創(chuàng)建UDP套接字
SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0); SOCKADDR_IN addrSrv;
接收數(shù)據(jù)
char recvBuf[100]; recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);
發(fā)送數(shù)據(jù)
char sendBuf[] = "hello Client,I'm Server!\n"; sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);
關(guān)閉
closesocket(sockSrv); WSACleanup();
具體實(shí)現(xiàn)代碼:
#include <WinSock2.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") int main(void) { // 初始化套接字庫 WORD wVersion; WSADATA wsaData; int err; wVersion = MAKEWORD(1, 1); err = WSAStartup(wVersion, &wsaData); if (err != 0) { return err; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return -1; } // 創(chuàng)建UDP套接字 SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6001); SOCKADDR_IN addrCli; int len = sizeof(SOCKADDR); char sendBuf[] = "hello, I'm Client!\n"; char recvBuf[100]; std::cout << "send to Server: " << sendBuf << std::endl; sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len); recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len); std::cout << "recv from: " << recvBuf << std::endl; closesocket(sockCli); WSACleanup(); system("pause"); return 0; }
運(yùn)行效果:
總結(jié)
socket的具體細(xì)節(jié)用法我不太清楚,現(xiàn)階段也只是熟悉TCP的一些簡單操作,UDP的話也還不是太懂,不懂的是不知道在具體項(xiàng)目中該如何進(jìn)行使用它們。
那個TCP的小項(xiàng)目也只是自己琢磨搞出來的,不知掉具體項(xiàng)目會不會這樣去寫!
到此這篇關(guān)于C++ Socket實(shí)現(xiàn)TCP與UDP網(wǎng)絡(luò)編程的文章就介紹到這了,更多相關(guān)C++ Socket實(shí)現(xiàn)TCP與UDP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++如何比較兩個字符串或string是否相等strcmp()和compare()
這篇文章主要介紹了C++如何比較兩個字符串或string是否相等strcmp()和compare()問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11C語言 function recursion函數(shù)遞歸詳解
遞歸指的是在函數(shù)的定義中使用函數(shù)自身的方法,舉個例子: 從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!故事是什么呢?"從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!故事是什么呢?"從前有座山,山里有座廟,循環(huán)下去2021-10-10C++調(diào)用libcurl開源庫實(shí)現(xiàn)郵件的發(fā)送功能流程詳解
libcurl是一個免費(fèi)開源的網(wǎng)絡(luò)傳輸庫,支持ftp、ftps、tftp,http、https、telnet、ldap、pop3、smtp等多種協(xié)議,接下來讓我們一起來了解吧2021-11-11Qt+OpenCV實(shí)現(xiàn)目標(biāo)檢測詳解
這篇文章主要介紹了如何利用Qt和OpenCV中自帶xml文件實(shí)現(xiàn)目標(biāo)檢測,文中的實(shí)現(xiàn)過程講解詳細(xì),感興趣的小伙伴可以動手試一試2022-03-03C++拷貝構(gòu)造函數(shù)(深拷貝與淺拷貝)詳解
深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當(dāng)這個類的對象發(fā)生復(fù)制過程的時(shí)候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝2013-09-09C語言創(chuàng)建動態(tài)dll和調(diào)用dll(visual studio 2013環(huán)境下)
本篇文章主要介紹了C語言創(chuàng)建動態(tài)dll和調(diào)用dll(visual studio 2013環(huán)境下),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-11-11