Linux网络:socket编程UDP

文章目录

  • 前言
  • 一,socket
  • 二,服务端socket
    • 3-1 创建socket
    • 3-2 绑定地址和端口
    • 3-3 接收数据
    • 3-4 回复数据
    • 3-5关闭socket
    • 3-6 完整代码
  • 三,客户端socket
    • 3-1 为什么客户端通常不需要手动定义 IP 和端口


前言

学习 socket 编程的意义在于:它让你掌握计算机之间通信的核心原理,能亲手实现聊天程序、文件传输、简易服务器等网络应用;同时这是理解 TCP/IP 协议、深入系统编程和进入后台开发、分布式系统的基础技能,也是面试和工程实践中必不可少的知识。


一,socket

socket(套接字) 是操作系统提供的一种 通信机制,最常用于网络通信,在编程时,你可以把它当作 特殊的文件描述符(FD),既能读、也能写,文件用来在本地磁盘读写数据,而 socket 用来在不同主机之间交换数据。你可以把 socket 看作网络文件,只是读写的数据不是在磁盘上,而是发送到网络上的另一个进程。


二,服务端socket

主要作用:接收客户端请求并回复,服务器端使用socket分为几个阶段:创建 socket -> 绑定地址和端口 -> 等待客户端发送数据 / 监听连接 -> 处理数据或回复 -> 关闭 socket


3-1 创建socket

socket函数原型

int socket(int domain, int type, int protocol);
  • domain:用于选择网络协议协议类型一般有值:AF_INET (IPv4 网络协议),AF_INET6 (IPv6 网络协议),AF_UNIX/AF_LOCAL (本地进程间通信)
  • type:指定传输方式,主要有两种:SOCK_STREAM 面向连接,基于字节流(TCP),SOCK_DGRAM 无连接,基于报文(UDP)
  • protocol:通常指定具体协议:0 默认协议,IPPROTO_TCP 明确选择 TCP,IPPROTO_UDP 明确选择 UDP

在下面的代码示例中我们会选择:

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

创建一个UDP的套接字


3-2 绑定地址和端口

struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY; // 任意 IP
servaddr.sin_port = htons(12345);      // 端口
bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

上面的struct sockaddr_in servaddr创建一个 IPv4 地址结构体 sockaddr_in,用来保存服务端的 IP 地址和端口信息结构体定义大致如下:

struct sockaddr_in {short            sin_family;   // 地址族 (AF_INET)unsigned short   sin_port;     // 端口号struct in_addr   sin_addr;     // IP 地址char             sin_zero[8];  // 填充为与 struct sockaddr 同大小
};

解释上述代码:

servaddr.sin_family = AF_INET;

设置 地址族为 IPv4 (AF_INET)告诉内核这是一个 IPv4socket

servaddr.sin_addr.s_addr = INADDR_ANY; // 任意 IP

INADDR_ANY = 0.0.0.0,表示服务端 绑定本机所有可用 IP 地址,如果服务器有多个网卡,客户端发送到任意 IP 都能被接收

servaddr.sin_port = htons(12345); // 端口

设置端口号为 12345htons = host to network short(主机字节序 → 网络字节序),网络通信使用 大端序,保证不同平台可以正确解析端口

bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

bind() socket 文件描述符 与 IP + 端口 绑定

参数解释:

sockfd:之前 socket() 返回的文件描述符

(struct sockaddr*)&servaddr : 地址信息,强制类型转换为通用 sockaddr

sizeof(servaddr) : 结构体大小


3-3 接收数据

char buffer[100];
struct sockaddr_in cliaddr {};
socklen_t len = sizeof(cliaddr);int n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr * ) & cliaddr, & len);

这段代码在一个 UDP 服务器程序中,从客户端接收数据,存储到 buffer 中,同时记录客户端的地址信息cliaddr,并返回接收的字节数n

char buffer[100];

定义一个字符数组 buffer,大小为 100 字节,用来存储从客户端接收的数据

struct sockaddr_in cliaddr {};

定义一个 sockaddr_in 结构体变量 cliaddr,用于存储客户端的地址信息(如 IP 地址和端口号)。{} 初始化所有字段为 0

socklen_t len = sizeof(cliaddr);

定义一个 socklen_t 类型的变量 len,初始化为 cliaddr 的大小(通常 16 字节,struct sockaddr_in 的大小)。


3-4 回复数据

const char* reply = "Hello Client";sendto(sockfd, reply, strlen(reply), 0, (struct sockaddr*)&cliaddr, len); // 回复

这段代码用与服务器回复客户端信息

其它的不再过多赘述

(struct sockaddr*)&cliaddr:客户端地址结构体,告诉内核消息发送到哪里


3-5关闭socket

close(sockfd);

不关闭会造成资源泻漏


3-6 完整代码

#include <iostream>
#include <arpa/inet.h>
#include <unistd.h>int main() {int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建 UDP socketif (sockfd < 0) { perror("socket"); return -1; }sockaddr_in servaddr{};servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port = htons(12345);bind(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)); // 绑定端口char buffer[100];sockaddr_in cliaddr{};socklen_t len = sizeof(cliaddr);int n = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (sockaddr*)&cliaddr, &len); // 接收消息buffer[n] = '\0';std::cout << "Server received: " << buffer << std::endl;const char* reply = "Hi Client";sendto(sockfd, reply, strlen(reply), 0, (sockaddr*)&cliaddr, len); // 回复客户端close(sockfd);return 0;
}

三,客户端socket

客户端socket代码我直接展示出来吧,我们理解了服务端之后,客户端是非常好理解的

#include <iostream>
#include <arpa/inet.h>
#include <unistd.h>int main() {int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建 UDP socketif (sockfd < 0) { perror("socket"); return -1; }sockaddr_in servaddr{};servaddr.sin_family = AF_INET;servaddr.sin_port = htons(12345);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 本机测试const char* msg = "Hello Server";sendto(sockfd, msg, strlen(msg), 0, (sockaddr*)&servaddr, sizeof(servaddr)); // 发送消息char buffer[100];socklen_t len = sizeof(servaddr);int n = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (sockaddr*)&servaddr, &len); // 接收回复buffer[n] = '\0';std::cout << "Client received: " << buffer << std::endl;close(sockfd);return 0;
}

这里的sendtorecvfrom大家应该都懂,主要是这个客户端是如何找到服务端的重要

    sockaddr_in servaddr{};servaddr.sin_family = AF_INET;servaddr.sin_port = htons(12345);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 本机测试

在这段代码里的IP地址和端口号是找到服务端的关键

  • IP 地址 (127.0.0.1):告诉客户端要把数据发送到哪个机器。127.0.0.1 表示本机,也就是服务端和客户端在同一台电脑。如果服务端在另一台电脑,你就要写它的真实 IP,例如 192.168.1.100

  • 端口号 (12345)
    服务端在这个端口上监听数据。UDP/TCP 都是靠端口区分不同服务的,就像房子门牌号一样。所以客户端通过 IP, port 就能找到服务端。


3-1 为什么客户端通常不需要手动定义 IP 和端口

客户端的职责是 主动找服务端,在调用 sendto()时:目标地址(服务端的 IP+端口) 由程序员指定,源地址(客户端的 IP+端口) 不写时由内核自动分配

IP:自动选择一块能到达服务端的本地网卡的 IP

端口:自动分配一个 临时端口,通常在 49152–65535 之间

客户端什么时候需要绑定 IP+端口:如果客户端希望 使用固定端口(比如做 P2P、游戏服务器通知端口),或者有多张网卡,必须指定 用哪张网卡的 IP 去通信,这种情况才会手动调用 bind()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/922414.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/922414.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【从零到公网】本地电脑部署服务并实现公网访问(IPv4/IPv6/DDNS 全攻略)

从零到公网&#xff1a;本地电脑部署服务并实现公网访问&#xff08;IPv4/IPv6/DDNS 全攻略&#xff09; 适用场景&#xff1a;本地 API 服务、大模型推理服务、NAS、远程桌面等需要公网访问的场景 关键词&#xff1a;公网 IP、端口映射、内网穿透、IPv6、Cloudflare DDNS 一、…

模块二 落地微服务

11 | 服务发布和引用的实践 服务发布和引用常见的三种方式&#xff1a;Restful API、XML配置以及IDL文件。今天我将以XML配置方式为例&#xff0c;给你讲解服务发布和引用的具体实践以及可能会遇到的问题。 XML配置方式的服务发布和引用流程 1. 服务提供者定义接口 服务提供者发…

C++程序员速通C#:从Hello World到数据类型

C程序员光速入门C#&#xff08;一&#xff09;&#xff1a;总览、数据类型、运算符 一.Hello world&#xff01; 随着.NET的深入人心,作为一个程序员&#xff0c;当然不能在新技术面前停而止步&#xff0c;面对着c在.net中的失败,虽然有一丝遗憾&#xff0c;但是我们应该认识到…

Linux相关概念和易错知识点(44)(IP地址、子网和公网、NAPT、代理)

目录1.IP地址&#xff08;1&#xff09;局域网和公网①局域网a.网关地址b.局域网通信②运营商子网③公网&#xff08;2&#xff09;NAPT①NAPT过程②理解NAPT③理解源IP和目的IPa.目的IPb.源IP③最长前缀匹配④NAT技术缺陷2.代理服务&#xff08;1&#xff09;正向代理&#xf…

工业智能终端赋能自动化生产线建设数字化管理

在当今数字化浪潮的推动下&#xff0c;自动化生产线正逐渐成为各行各业提升效率和降低成本的重要选择。随着智能制造的深入发展&#xff0c;工业智能终端的引入不仅为生产线带来了技术革新&#xff0c;也赋予了数字化管理新的动力。一、工业智能终端&#xff1a;一体化设计&…

【Vue2手录06】计算属性Computed

一、表单元素的v-model绑定&#xff08;核心场景&#xff09; v-model 是Vue实现“表单元素与数据双向同步”的语法糖&#xff0c;不同表单元素的绑定规则存在差异&#xff0c;需根据元素类型选择正确的绑定方式。 1.1 四大表单元素的绑定规则对比表单元素类型绑定数据类型核心…

FPGA入门-数码管静态显示

19. 数码管的静态显示 在许多项目设计中&#xff0c;我们通常需要一些显示设备来显示我们需要的信息&#xff0c;可以选择的显示设备有很多&#xff0c;而数码管是使用最多&#xff0c;最简单的显示设备之一。数码管是一种半导体发光器件&#xff0c;具有响应时间短、体积小、…

深入理解大语言模型(5)-关于token

到目前为止对 LLM 的描述中&#xff0c;我们将其描述为一次预测一个单词&#xff0c;但实际上还有一个更重要的技术细 节。即 LLM 实际上并不是重复预测下一个单词&#xff0c;而是重复预测下一个 token 。对于一个句子&#xff0c;语言模型会 先使用分词器将其拆分为一个个 to…

视觉智能的「破壁者」——Transformer如何重塑计算机视觉范式?三大CV算法论文介绍 ViTMAESwin Transformer

当自然语言处理领域因Transformer而焕发新生时&#xff0c;计算机视觉却长期困于卷积神经网络的架构桎梏。直到ViT&#xff08;Vision Transformer&#xff09;的横空出世&#xff0c;才真正打破了视觉与语言之间的壁垒。它不仅是技术的革新&#xff0c;更是范式革命的开始&…

Java 并发容器源码解析:ConcurrentSkipListSet 行级深度剖析

Java 并发容器源码解析&#xff1a;ConcurrentSkipListSet 行级深度剖析 本文将深入解析 Java 并发容器 ConcurrentSkipListSet 的核心源码&#xff0c;结合流程图、代码注释、设计思想、优缺点分析、业务场景、调试与优化、集成方案、高阶应用等&#xff0c;帮助你系统掌握这款…

答题卡自动识别案例

目录 1.答题卡自动批阅整体实现思路 2.关键技术步骤与原理 答题卡区域提取 ①轮廓检测并排序 ②执行透视变换 ③找到每一个圆圈轮廓 ④先对所有圆圈轮廓从上到下排序 ⑤再通过循环每次只提取出五个轮廓再进行从左到右的排序 3.完整代码 1.答题卡自动批阅整体实现思路 …

C#实现通过POST实现读取数据

C# POST请求与MySQL数据存储实现下面是一个完整的C#解决方案&#xff0c;用于发送POST请求、接收响应数据&#xff0c;并将数据保存到MySQL数据库中。完整代码实现 using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.J…

Java 字符编码问题,怎么优雅地解决?

网罗开发&#xff08;小红书、快手、视频号同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

STL之string类(C++)

1.string类核心定位std::string 本质是对 “字符序列” 的封装&#xff0c;内部通过动态数组存储字符&#xff0c;并自动管理内存&#xff08;分配、扩容、释放&#xff09;&#xff0c;对外提供了简洁的接口用于字符串的创建、修改、拼接、查找等操作。1.1 使用前提头文件包含…

[Maven 基础课程]第一个 Maven 项目

idea 新建一个项目&#xff1a; 来到 New Project 页面&#xff1a; 这里我们有两种方式创建 maven 项目&#xff0c;一种是自定义创建&#xff0c;另一种是使用 maven 模版项目创建。 自定义创建 maven 项目 基本配置 Name: first_maven_project 项目名称&#xff0c;设为 …

uni小程序中使用Echarts图表

前言 今天鸡米花给大家带来的是在uni里面使用echarts&#xff0c;能够完美支持和PC端一样的效果&#xff0c;我这边的工程是uni转为微信小程序&#xff0c;用的是vue3vite来写的&#xff0c;然后实现了竖屏和横屏的展示方式&#xff0c;好了献上效果图。 效果图 一、引入插件 这…

从FOTA测试到汽车电子安全体系的启蒙之旅

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

stm32中 中断和事件的区别

一、核心概念比喻想象一下工厂里的一个报警系统&#xff1a;​中断 (Interrupt)​​&#xff1a;就像火警警报器响了。它的目的是通知管理员&#xff08;CPU&#xff09;​​&#xff1a;“着火了&#xff01;”。管理员听到后&#xff0c;会停下手中的工作&#xff08;保存现场…

深入理解MySQL主从架构中的Seconds_Behind_Master指标

问题&#xff1a;主从延迟与写后读不一致 在典型的 MySQL 主从架构下&#xff0c;所有写操作都会直接进入主库&#xff0c;而读操作大多分流到从库&#xff0c;从而实现读写分离&#xff0c;缓解主库压力。 然而 MySQL 的复制机制是异步的&#xff1a;主库先写入 binlog&#…

MySQL安装(linux版本)

MySQL安装&#xff08;linux版本&#xff09; 课程地址 08. 进阶-MySQL安装(linux版本)_哔哩哔哩_bilibili 安装过程中所有需要的程序都放在网盘里了 通过网盘分享的文件&#xff1a;虚拟机 链接: https://pan.baidu.com/s/1eLMD2iq1uEujNN7mWs2dIg?pwdckmh 提取码: ckmh …