網絡實踐——Socket編程UDP

文章目錄

  • Socket編程UDP
    • UDP接口的使用鋪墊
      • socket
      • recvform && sendto
      • bind
    • 字節序轉化使用(Tips)
    • 實踐部分
      • version_1@echo_server
      • version_2@dict_server
      • version_3@chat_server

Socket編程UDP

在了解了相關的網絡基礎知識后,我們不會像學系統知識一樣,先學原理,再講應用。
我們先先不選擇學習網絡原理。我們先來試著學習一下使用接口來完成一些簡單地實踐。

在這個部分中,我們不只使用網絡相關知識,而是結合前面系統部分學習時,完成的一些組件代碼來使用!這些我們后面會見到的!

UDP接口的使用鋪墊

先說一下,有了網絡基礎知識 + 系統部分的知識。其實我們只需要了解一下UDP相關接口的使用,其實就能較為熟練地學習如何使用。下面,我們將把網絡中將用的接口進行簡單講解。

socket

NAMEsocket - create an endpoint for communication //打開通信的一端SYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);

這個文件,是用來創建套接字的!我們在網絡基礎部分講過,兩個進程的通信是基于套接字(端口號 + ip)的!具體的創建,就是用這個接口。

第一個參數domain是選擇使用什么域來進行通信:
在這里插入圖片描述
這里我們記住是選擇AF_INET進行網絡通信即可!

第二個參數type是選擇使用什么方式傳輸,比如TCP/UDP:
在這里插入圖片描述
字符流 -> SOCK_STREAM -> TCP
數據包 -> SOCK_DGRAM -> UDP

第三個參數protocol是要我們選擇協議,默認給0就是TCP/IP了,記住即可!

返回值:
在這里插入圖片描述
成功,返回一個file descriptor,即文件描述符!即使我們不知道這個網絡通信的原理,但是我們至少可以直到,當前進程的文件描述符表定會有一個位置指向socket文件!

所以,我們就把它當成特殊的網絡文件來使用!這符合 Linux下一切皆文件!

recvform && sendto

我們先來看著兩個函數的相關信息,它們具有較強相似性:

recvform

NAMErecv, recvfrom, recvmsg - receive a message from a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);RETURN VALUEThese calls return the number of bytes received, or -1 if an error occurred.  In the event of an error, errno is set to indicate the error.

sendto

NAMEsend, sendto, sendmsg - send a message on a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);RETURN VALUEOn success, these calls return the number of bytes sent.  On error, -1 is returned, and errno is set appropriately.

見名思意:
recvform是從套接字文件中獲取內容;sendto是向套接字文件中發送內容。


參數解釋:

  1. int sockfd,就是對應的套接字文件!這個不需要解釋。

  2. const void *buf,這個就是一個緩沖區,recvfrom把從套接字文件中讀到的內容讀取到該緩沖區。sendto將該緩沖區內的內容發送到套接字文件。

  3. size_t len,即緩沖區長度。

  4. int flags,這個是選擇是否阻塞讀取/發送的。默認給0就是阻塞。也就是說,recvfrom讀不到內容就會阻塞,sendto沒有內容發送也會阻塞。這個我們在系統那里也見過。

  5. struct sockaddr,這個其實我們早在網絡基礎部分的時候,就已經講到過這個。我們說了,設計socket網絡通信的時候,為了能夠讓網絡通信和本地通信公用一套接口,所以設計了這么個c語言版的基類

    所以,如果需要收發消息,其實對方進程的相關信息:ip、端口號、通信協議,都會在對應的結構體上體現出來。所以,未來在使用socket通信的時候,如何知道或者發送自己的相關信息,就是靠著這個結構體sockaddr_in或者sockaddr_un,強轉類型為sockaddr對應的地址變量后,然后進行相關操作!

6.socklen_t *addrlensocklen_t addrlen
6.1. 對于recvfrom收消息來說,參數是socklen_t *addrlen,這很明顯是一個指針地址變量!所以,是需要我們把sockaddr_in的地址傳進去給第五個參數,然后需要定義一個變量指明該結構體大小,傳入地址給第六個參數。
Tips:因為該變量是輸出型參數,實際上它會返回真正讀到的字節數(因為網絡傳輸可能丟包)

6.2. 對于sendto發消息來說,這個就沒什么好說的了,本身數據就在,直接傳對應的大小即可

bind

NAMEbind - bind a name to a socketSYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);RETURN VALUEOn success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

沒看錯,這里還有一個接口叫做bind,但是,這個不是c++11后提出的std::bind

這個接口最重要的就是,將套接字文件和對應的進程的IP地址和端口號(在結構體sockaddr_in內存儲了),綁定到對應的套接字文件中!

??bind的作用??:
顯式綁定:bind()將套接字固定到特定IP+端口,成為該地址的唯一接收者。
未綁定時:系統在首次發送數據時自動分配隨機端口(IP默認為所有本地接口)

這里理解一下就好,實在看不懂的話等后續講解的時候再說一遍如何使用。現在只需要學會使用即可,原理等后期再來講解!

字節序轉化使用(Tips)

這個在網絡基礎中也是提到了。這里再多提醒一下,因為后續的實踐中,必然是有從網絡序列轉主機序列的內容,也有主機序列轉網絡序列的!所以,這些是必須使用的!
在這里插入圖片描述

實踐部分

version_1@echo_server

源碼:version_1@echo_server

第一個版本,我們希望實現一種功能:
即有一個服務器,然后其余所有的進程都可以給其發消息,然后服務器處理后再轉發給對應的進程,這樣子就起到了一個回顯服務器的效果!

所有的過程都已經在代碼的注釋中展現出來了。

version_2@dict_server

源碼:version_2@dict_server

第二個版本,其實就是進行一次解耦合!讓第一個版本中對于信息回顯的處理模塊,轉化為服務器調用詞典翻譯模塊!其實主要的邏輯和第一個版本差別不大。

只不過是引入多了一個模塊,讓詞典從對應的配置文件中讀取對應信息,然后服務器進行調用后再進行轉發結果給請求該服務的進程!

version_3@chat_server

源碼:version_3@chat_server

第三個版本我們來詳細說明一下:
第三個版本我們希望做到一個群聊轉發功能,即服務器在接收到某個客戶端發送來的消息后,要轉發給所有處于在線的用戶。

1.我們這里規定:
默認第一次發送消息的就是要加入群聊的。服務器接收到消息之后,要怎么樣才能轉發給所有的在線用戶呢?-> 添加一層路由層,用于管理在線用戶(組織描述)和消息轉發!

2.但是,我們覺得效率太低了,所以希望的是,服務器將收到的信息推給后端線程池,讓線程池自行調用路由轉發功能!所以引入了線程池。

3.此前版本1、2寫的客戶端使用代碼是有問題的!因為強行規定了先發消息才能收消息。所以,在實現群聊過程中,發現客戶端只有發了消息,才能接收到其他客戶端被轉發的消息。所以,為此我們進行了處理,就是讓客戶端多線程處理!即創建兩個線程,同時進行收發!

4.線程池訪問路由表的時候(就是底層的一個哈希),也是會涉及到線程安全的。但是,因為今天的實現并沒有規定消息的協議(是否退出、私法、群發、還是請求服務器處理…)。我們僅僅只是把收到的內容當字符串處理!
但是不管怎么說,線程池內每個線程訪問的時候,是會出現數據不一致的問題的!因為STL不是線程安全的,所以我們這里就粗暴一點,直接加鎖!

5.實踐的時候,因為我沒有多臺Linux機器,所以,使用了Windows進行輔助測試,測試是否能夠跨網通信!代碼如下:

#include <iostream>
#include <cstdio>
#include <thread>
#include <string>
#include <cstdlib>
#include <WinSock2.h>
#include <Windows.h>#pragma warning(disable : 4996)#pragma comment(lib, "ws2_32.lib")std::string serverip = "";  // 填寫你的云服務器ip
uint16_t serverport = ; // 填寫你的云服務開放的端口號SOCKET sockfd; 
struct sockaddr_in server;void recv_msg() {while (1) {char buffer[1024];struct sockaddr_in temp;int len = sizeof(temp);int s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);if (s > 0){buffer[s] = 0;std::cout << buffer << std::endl;}}
}void send_msg() {memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(serverport); //? server.sin_addr.s_addr = inet_addr(serverip.c_str()); while (1) {std::string message; std::getline(std::cin, message);if (message.empty()) continue; sendto(sockfd, message.c_str(), (int)message.size(), 0, (struct sockaddr*)&server, sizeof(server));}
}int main() {WSADATA wsd; WSAStartup(MAKEWORD(2, 2), &wsd); sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == SOCKET_ERROR){std::cout << "socker error" << std::endl;return 1;}std::thread Recv(recv_msg);std::thread Send(send_msg);Recv.join();Send.join();closesocket(sockfd);WSACleanup();return 0;
}//int main()
//{
//    WSADATA wsd;
//    WSAStartup(MAKEWORD(2, 2), &wsd);
//
//
//    memset(&server, 0, sizeof(server));
//    server.sin_family = AF_INET;
//    server.sin_port = htons(serverport); //?
//    server.sin_addr.s_addr = inet_addr(serverip.c_str());
//
//    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
//    if (sockfd == SOCKET_ERROR)
//    {
//        std::cout << "socker error" << std::endl;
//        return 1;
//    }
//
//
//
//    std::string message;
//    char buffer[1024];
//    while (true)
//    {
//        std::cout << "please input: ";
//        std::getline(std::cin, message);
//        if (message.empty()) continue;
//        sendto(sockfd, message.c_str(), (int)message.size(), 0, (struct sockaddr*)&server, sizeof(server));
//        struct sockaddr_in temp;
//        int len = sizeof(temp);
//        int s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);
//        if (s > 0)
//        {
//            buffer[s] = 0;
//            std::cout << buffer << std::endl;
//        }
//    }
//
//    closesocket(sockfd);
//    WSACleanup();
//    return 0;
//}

前面一份是用于版本3的測試,后面是用于版本1、2的測試!這里可以搜一下相關大模型了解一下用法,其實用法和Linux下的基本一致。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94161.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94161.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94161.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GD32 波形發生器,三角波,正弦波,方波。AD9833+MCP410生成和MCU自身的DAC生成。波形,頻率,振幅可以通過按鍵和OLED調整輸出。

DIY一個簡易的信號發生器驅動板&#xff0c;主要是三角波和正弦波&#xff0c;方波。主板有兩個通道能輸出波形&#xff0c;CH0由AD9833MCP410AD8051放大電路組成&#xff0c;理論可以生成0.1-12.5MHZ的頻率信號&#xff0c;單電源振幅范圍是1-9V。CH1由MCU外設DAC生成的信號&a…

VS2022的MFC中關聯使用控制臺并用printf輸出調試信息

前言 MFC一般在調試的時候&#xff0c;可以在IDE中方便的看到調試的信息。但是&#xff0c;有時候運行的時候也要看調試的信息怎么辦&#xff1f;最好如同在Console&#xff08;控制臺&#xff09;程序中輸出一般的方便&#xff0c;可以么&#xff1f;可以的。 一、設置 1.1、加…

ZKmall模塊商城的推薦數據體系:從多維度采集到高效存儲的實踐

在電商領域&#xff0c;個性化推薦已成為提升用戶體驗與轉化效率的核心手段。ZKmall 模塊商城基于用戶行為、商品屬性與交易數據&#xff0c;構建了一套完整的推薦算法體系&#xff0c;而數據采集的全面性與存儲的高效性是該體系的基礎。本文將聚焦推薦算法的 “數據輸入端”&a…

Qt + windows+exe+msvc打包教程

目錄 1. Qt + windows+exe+msvc打包教程1 1.1. Enigma Virtual Box下載?1 1.2. Enigma Virtual Box安裝2 1.3. Qt 打包成獨立exe教程6 1.3.1. Qt項目創建6 1.3.2. Qt項目編譯13 1.3.3. Qt 項目打包 windeployqt命令14 1.3.4. Qt 項目打包 Enigma Virtual Box工具18 Q…

大語言模型應用開發——利用OpenAI函數與LangChain結合從文本構建知識圖譜搭建RAG應用全流程

概述 從文本等非結構化數據中提取結構化信息并非新鮮事物&#xff0c;但大語言模型&#xff08;LLMs&#xff09;為該領域帶來了重大變革。以往需要機器學習專家團隊策劃數據集并訓練自定義模型&#xff0c;如今只需訪問LLM即可實現&#xff0c;顯著降低了技術門檻&#xff0c…

Vue3+Spring Boot技術棧,前端提交混合表單數據(普通字段+文件字段),上傳文件,后端插入數據,將文件保存到數據庫

一、技術棧1、前端 Vue3 Element Plus TypeSprict2、后端 Spring Boot 3.2.12 Mybatis Plus3、模型特點3.1、表格展示列表數據3.2、行點擊&#xff0c;彈出對話框3.3、前端使用 FormData 提交混合表單數據&#xff0c;包含普通字段和文件字段3.4、文件對應數據庫結構類型為 …

【Qt開發】Qt的背景介紹(四)

目錄 1 -> Qt Hello World 程序 1.1 -> 使用“按鈕”實現 1.1.1 -> 純代碼方式實現 1.1.2 -> 可視化操作實現 1.2 -> 使用“標簽”實現 1.2.1 -> 純代碼方式實現 1.2.2 -> 可視化操作實現 2 -> 項目文件解析 2.1 -> .pro文件解析 2.2 -&g…

Linux驅動開發筆記(六)——pinctrl GPIO

開發板&#xff1a;imx6ull mini 虛擬機&#xff1a;VMware17 ubuntu&#xff1a;ubuntu20.04 視頻&#xff1a;第8.1講 pinctrl和gpio子系統試驗-pincrl子系統詳解_嗶哩嗶哩_bilibili 文檔&#xff1a;《【正點原子】I.MX6U嵌入式Linux驅動開發指南.pdf》四十五章 這一章…

SpringBoot 快速上手:從環境搭建到 HelloWorld 實戰

在 Java 開發領域&#xff0c;Spring 框架占據著舉足輕重的地位&#xff0c;但它復雜的配置曾讓不少開發者望而卻步。SpringBoot 的出現&#xff0c;如同為 Spring 框架裝上了 “加速器”&#xff0c;以 “約定大于配置” 的理念簡化了開發流程。本文將從環境準備、Maven 配置入…

圖、最小生成樹與最短路徑

目錄 并查集 并查集實現 圖 概念 圖的存儲結構 鄰接矩陣 鄰接表 無向圖 有向圖 圖的遍歷 廣度優先遍歷 深度優先遍歷 最小生成樹 Kruskal算法&#xff08;克魯斯卡爾算法&#xff09; Prim算法&#xff08;普利姆算法&#xff09; 最短路徑 單源最短路徑--Dij…

互聯網電商新生態:開源AI智能名片、鏈動2+1模式與S2B2C商城小程序的融合賦能

摘要&#xff1a;本文聚焦互聯網電商領域&#xff0c;探討在當下直播電商蓬勃發展的背景下&#xff0c;開源AI智能名片、鏈動21模式以及S2B2C商城小程序如何相互融合&#xff0c;為創業者、企業和淘寶主播IP等電商參與者帶來新的發展機遇。通過分析各要素的特點與優勢&#xff…

企業車輛|基于SprinBoot+vue的企業車輛管理系統(源碼+數據庫+文檔)

企業車輛管理系統 基于SprinBootvue的企業車輛管理系統 一、前言 二、系統設計 三、系統功能設計 系統功能實現 后臺模塊實現 管理員模塊實現 駕駛員模塊實現 四、數據庫設計 五、核心代碼 六、論文參考 七、最新計算機畢設選題推薦 八、源碼獲取&#xff1a; 博…

自學嵌入式第二十五天:數據結構-隊列、樹

一、隊列隊列是只允許一段進行插入&#xff0c;另一端進行刪除操作的線性表&#xff1b;允許插入的一端叫隊尾&#xff0c;允許刪除的一端叫對頭&#xff1b;先進先出&#xff1b;用于解決速度不匹配&#xff08;例如一快一慢&#xff09;&#xff0c;做緩沖用&#xff1b;二、…

MySQL索引原理與優化全解析

1、MySQL索引是什么&#xff1f; 在關系數據庫中&#xff0c;索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構&#xff0c;它是某個表中一列或若干列值的集合和相應的指向表中物理標志這些值的數據頁的邏輯指針清單。索引的作用相當于圖書的目錄&a…

模型對話狀態管理方法詳解

模型對話狀態管理方法詳解 目錄 簡介手動管理對話狀態構建對話歷史追加響應內容 API 支持的自動化對話狀態管理使用 previous_response_id 鏈接話輪 Token 及上下文窗口管理上下文窗口定義與限制Token 計數與工具 安全與合規注意事項結語1. 簡介 在多輪對話場景中&#xff0c;合…

GPT-5 上線風波深度復盤:從口碑兩極到策略調整,OpenAI 的變與不變

摘要&#xff1a; 近日&#xff0c;備受矚目的 GPT-5 正式上線&#xff0c;卻意外地在社區引發了兩極化爭議。面對技術故障與用戶質疑&#xff0c;OpenAI 迅速推出一系列補救措施。本文將深度復盤此次發布風波&#xff0c;解析其背后的技術挑戰與應對策略&#xff0c;并探討這一…

【Android】使用FragmentManager動態添加片段

三三要成為安卓糕手 上一篇文章&#xff0c;我們是在xml中靜態添加fragment&#xff0c;但是一些修改或者其他事情是做不了的&#xff1b; 本章我們達成在java代碼中靈活添加、刪除、替換fragment操作 一&#xff1a;核心代碼展示 簡單做一個這種頁面public class FragmentActi…

MiniOB環境部署開發(使用開源學堂)

整體思路&#xff1a; 1.使用開源學堂在線編程環境開發MiniOB編譯環境 2.使用vscode進行代碼調試和開發以及上傳到倉庫 MiniOB源碼&#xff1a;https://github.com/oceanbase/miniob MiniOB文檔&#xff1a;MiniOB 介紹 - MiniOB 數據庫大賽官網&#xff1a;OceanBase 社區…

09_常用內置模塊進階

第9課&#xff1a;常用內置模塊進階 課程目標 深入學習Python常用內置模塊掌握collections、itertools、functools等模塊學習json、csv、pickle等數據處理模塊 1. collections模塊 1.1 Counter類 from collections import Counter# 統計元素出現次數 text "hello world p…

? Ranger 基礎命令與功能詳解

&#x1f4cc; 1. Ranger簡介 Ranger&#xff08;游俠&#xff09;是一款 Linux 專用的 指令式文件管理器&#xff0c;其操作風格類似 Vim&#xff0c;通過輸入指令即可完成目錄跳轉、文件編輯、移動、復制等操作。 相比于 mc&#xff08;Midnight Commander&#xff09;&…