Socket(套接字)详解 画图+实例

article/2025/10/20 20:48:13

Socket概念

Socket本意为“插座”,在Linux下,用于表示进程间网络通信的特殊文件类型,本质为内核借助缓冲区形成的伪文件
既然是文件,那肯定就可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。对于管道缓冲区,读端和写端的文件描述符分别指向缓冲区的两端,该缓冲区的工作是单向半双工的,从一端写,另一端读。而套接字缓冲区,一个文件描述符指向两个缓冲区,两端都可以读和写,这样才能实现双向全双工通信方式。
套接字的通信原理简单示意图如下,左端通过文件描述符将数据写入发送端缓冲区,右端从接受端缓冲区接受数据,也可以是左端读数据,右端写数据。左右的缓冲区之间就是通过套接字连接。可以看出,socket在通信过程中一定是成对出现(接受端socket和发送端socket)。
在这里插入图片描述
IP地址:在网络环境中唯一标识一台主机
端口号:在主机中唯一标识一个进程
IP+端口号:在网络环境中唯一标识一个进程,对应一个socket,欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接,因此就可以用socket来描述网络连接的一对一关系。

网络字节序

内存中的多字节数据相对于内存地址有大端和小端之分,网络数据流同样有大小端之分,网络数据流的地址这样规定:先发出的数据是低地址,后发出的数据是高地址。
大端存储:即数据的高字节存储在低地址处,低字节存储在高字节处
小段存储:即数据的低字节存储在底地址处,高字节存储在高地址处
如何测试电脑的大小端存储
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。
TCP/IP协议规定,网络数据流(网络字节顺序)采用大端字节序,即低地址存高字节。那如果接受端主机或者发送端主机采用的是小端字节序,就要做相应的网络字节序和主机字节序之间的转换。需要使用的函数为:htonl、htons、ntohl、ntohs。

IP地址转换

一般我们习惯用点分十进制表示IP,但是数据在网络中传输就要将其转换为TCP/IP中规定好的一种数据表示格式(网络字节顺序),这时就用到inet_pton函数,相反,网络字节序转换成用点分十进制表示的IP,用inet_ntop函数。

sockaddr_in数据结构

命令 man 7 ip可以查看到sockaddr_in的数据结构

struct sockaddr_in {sa_family_t    sin_family; /* address family: AF_INET */in_port_t      sin_port;   /* port in network byte order */struct in_addr sin_addr;   /* internet address */
};
/* Internet address. */
struct in_addr {uint32_t       s_addr;     /* address in network byte order */
};

sin_family:协议类型,IPV4还是IPV6
sin_port:端口号
sin_addr:IP地址

Socket函数

(1)socket函数:创建套接字
#include <sys/socket.h>
int socket(int af, int type, int protocol);
成功返回指向该套接字的文件描述符,失败返回-1
af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写,INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。
type 为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字,如TCP) 和 SOCK_DGRAM(数据报套接字/无连接的套接字,如UDP)。
protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。
(2)bind函数:绑定IP和端口号(struct sockaddr_in addr 初始化)
#include<sys/socket.h>
#include<sys/type.h>
int bind(int sockfd, const struct sockaddr * my_addr, socklen_t addrlen);
成功返回0,失败返回-1
sockfd 表示已经建立的socket编号(描述符)。
my_addr 是一个指向sockaddr结构体类型的指针。
addrlen表示my_addr结构的长度,可以用sizeof操作符获得。
(3)listen函数:指定同时支持的最大连接数
#include <sys/socket.h>
int listen( int sockfd, int backlog);
成功返回0,失败返回-1
sockfd表示文件描述符
backlog表示排队建立3次握手队列和刚刚建立3次握手队列的连接数之和
(4)accept函数:接受连接请求
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
成功返回一个新的socket文件描述符,用来和客户端通信,失败返回-1
sockfd表示文件描述符。
addr为传出参数,返回链接客户端地址信息,含IP地址和端口号。
addrlen为传入传出参数,传入sezeof(addr)的大小,函数返回时返回真正接受到地址结构体的大小。
(5)connect函数:建立与指定socket的连接
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
成功返回0,失败返回-1
s表示socket文件描述符。
addr为传入参数,指定服务器端地址信息,含IP地址和端口号
addrlen为传入参数,传入sezeof(addr)的大小

Socket模型创建流程图

对于客户端来说不需要调用bind函数,因为没有调用bind函数,操作系统会自动分配一个IP和端口号,但是服务器端不能使用随机分配的,比如,学生上课,教室必须指定固定的一间,否则学生无法找到,但是学生的地址是随机的。
在这里插入图片描述

Server端实现

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <ctype.h>
#include <arpa/inet.h>#define SERV_PORT 6666 //这里需要定义大点的端口号防止和系统已使用的冲突
int main(void){int lfd, cfd;struct sockaddr_in serv_addr, clie_addr;socklen_t clie_addr_len;char buf[BUFSIZ];int n, i;lfd = socket(AF_INET, SOCK_STREAM, 0);serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SERV_PORT);//主机字节序转网络字节序serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY是数字类型的IPbind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));listen(lfd, 128);//128为默认的上限值clie_addr_len = sizeof(clie_addr);cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);while(1){n = read(cfd, buf, sizeof(buf));for (i = 0; i < n; i++){buf[i] = toupper(buf[i]);}write(cfd, buf, n);}close(lfd);close(cfd);return 0;
}

编译:gcc socket_server.c -Wall -g
执行:./a.out

用nc命令测试 nc 127.0.0.1 6666
在这里插入图片描述

Client端实现

#include <sys/socket.h>
#include <stdlib.h>
#include <ctype.h>
#include <arpa/inet.h>#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666 //这里需要定义大点的端口号防止和系统已使用的冲突
int main(void){int cfd;struct sockaddr_in serv_addr;socklen_t serv_addr_len;char buf[BUFSIZ];int n;cfd = socket(AF_INET, SOCK_STREAM, 0);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SERV_PORT);//主机字节序转网络字节序inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);connect(cfd, (struct socketaddr *)&serv_addr, sizeof(serv_addr));while(1){fgets(buf, sizeof(buf),stdin);write(cfd,buf,strlen(buf));n = read(cfd,buf,sizeof(buf));write(STDOUT_FILENO, buf, n);}return 0;
}

总结

在server端,socket函数只是创建了套接字,并没有完成两个进程间通信,而是accept函数完成这件事,它返回一个套接字sfd,是一个文件描述符索引,read读sfd指向的缓冲区中的数据,write往sfd指向的缓冲区中写数据。在client端,通过fgets从标准输入缓冲区中读数据,然后通过write写到cfd指向的缓冲区中,然后通过IP+Port就能找到服务器端,服务器端的read就能读取到数据。详细描述为以下10个步骤:
在这里插入图片描述
注:该博文只是为了理解socket原理,所以代码中没有加函数返回正确或失败判断,实际编程中需要加上


http://chatgpt.dhexx.cn/article/YLOOZieM.shtml

相关文章

Python中的套接字编程

文章目录 **连接到服务器&#xff1a;****一个简单的服务器客户端程序&#xff1a;****服务器****客户端** 套接字编程是一种连接网络上的两个节点以相互通信的方法。一个套接字&#xff08;节点&#xff09;侦听 IP 处的特定端口&#xff0c;而另一个套接字则伸向另一个套接字…

流式套接字基本概念

目录 流式套接字基本概念创建套接字绑定本地地址连接请求监听函数接收请求套接字IO操作关闭套接字 编程实现 所谓套接字(Socket)&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利…

Windows下套接字

一、套接字 windows套接字Socket是进程通信的一种方式&#xff0c;可以实现在不同主机的相关进程之间交换数据。在TCP/IP网络应用中&#xff0c;通信的两个进程的主要模式是客户/服务器(C/S)模式&#xff0c;即客户向服务器发出请求&#xff0c;服务器接受到请求后&#xf…

深入理解Socket套接字原理

Socket套接字原理 1、什么是Socket 在计算机领域&#xff0c;套接字Socket作为计算机之间进行通信的固定的约定方式之一存在。这种太抽象了&#xff0c;我举个例子&#xff0c;我们要是用笔记本电脑前需要先对电脑供电&#xff0c;那供电就有两种方式电线插座供电和电池供电&…

原始套接字

一、原始套接字概述 协议栈的原始套接字从实现上可以分为“链路层原始套接字”和“网络层原始套接字”两大类。 链路层原始套接字可以直接用于接收和发送链路层的MAC帧&#xff0c;在发送时需要由调用者自行构造和封装MAC首部。而网络层原始套接字可以直接用于接收和发送IP层…

socket套接字

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 socket套接字 1. 什么是socket套接字2. socket编程3. 网络字节序4. IP地址转换函数5. sockaddr数据结构…

java 套接字是什么_套接字是什么,套接字通信及其原理

为通信的端点,每个套接字由一个 IP 地址和一个端口号组成。通过网络通信的每对进程需要使用一对套接字,即每个进程各有一个。 通常,套接字采用客户机-服务器架构。服务器通过监听指定端口,来等待客户请求。服务器在收到请求后,接受来自客户套接字的连接,从而完成连接。 实…

网络编程——原始套接字实现原理

目录 1. 基础知识 1.1、概述 1.2、链路层原始套接字 1.3、网络层原始套接字 2、原始套接字的实现 2.1 原始套接字报文收发流程 2.2链路层原始套接字的实现 2.2.1 套接字创建 2.2.2 报文接收 2.2.3 报文发送 2.2.4 其它 2.3 网络层原始套接字的实现 2.3.1 套接字…

UDP套接字编程

参考&#xff1a;《UNIX 网络编程 卷1 : 套接字联网API》 UDP 与 TCP 之间传输存在差异&#xff0c;也导致编写应用程序存在很多差异。UDP 客户端和服务器不建立连接&#xff0c;而是直接使用 sendto 函数给服务器发送数据报。但必须指定目的地的地址作为参数。服务器也不用接…

网络套接字编程

网络套接字编程 一、 认识UDP协议 UDP(User Datagram Protocol 用户数据报协议&#xff0c;是不可靠的数据报传输协议&#xff0c;不确保数据安全有序的到达对端。 特点&#xff1a; 传输层协议无连接不可靠传输面向数据报 应用场景&#xff1a;性能要求大于安全要求&…

彻底弄懂套接字

1.什么是套接字&#xff08;英文名&#xff1a;插座&#xff09; 套接字&#xff08;socket&#xff09;是一种通信机制&#xff0c;凭借这种机制&#xff0c;客户/服务器系统的开发工作既可以在本地单机上进行&#xff0c;也可以跨网络进行。Linux所提供的功能&#xff08;如打…

什么是套接字?Socket基本介绍

什么是套接字&#xff1f;Socket基本介绍 一、什么是套接字&#xff1f;二、套接字特性三、套接字缓冲区 一、什么是套接字&#xff1f; 套接字是一种通信机制&#xff08;通信的两方的一种约定&#xff09;&#xff0c;socket屏蔽了各个协议的通信细节&#xff0c;提供了tcp/…

微信小程序-引入地图、获得经纬度

实际这是一个获得经纬度的方法&#xff0c;但是有了经纬度可以做很多事情 点击按钮跳转到一个单独的页面&#xff08;地图&#xff0c;可导航&#xff09;在页面内嵌一个独立的小区域 首先可看一下腾讯地图官方文档 微信小程序JavaScript SDK | 腾讯位置服务 最基本&#xf…

微信小程序-批量地图标记

效果图 wxml <loading hidden"{{!loading}}">加载中</loading><view class"mapBox"><map id"myMap" scale"12" longitude"{{longitude}}" latitude"{{latitude}}" markers"{{mark…

实现地图功能 利用微信内置的微信地图

效果图&#xff1a; 查看微信开发文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/api/location/wx.chooseLocation.html 其实不难&#xff0c;查看官方文档&#xff0c;一目了然 直接上代码&#xff1a; map.wxml: <button bindtap"mapViewTap&…

微信小程序应用百度地图API

微信小程序&#xff0c;定位地点&#xff0c;应用bdmap API 1 申请 百度地图开放平台页面&#xff1a;控制台&#xff0c;添加应用 应用类型选微信小程序&#xff0c;添加微信小程序名称和APP ID 2. 微信小程序后台设置 进入微信公众平台&#xff0c;开发管理 服务器域名&a…

微信接入js-sdk-获取地理位置,打开微信内置地图

1.第一步当然是已经正确接入了微信并且配置好了回调安全域名。不会的朋友可以看看《微信开发-初级接入微信公众平台MP》 2. 引用微信js-sdk, http://res.wx.qq.com/open/js/jweixin-1.0.0.js&#xff0c;然后通过config接口注入权限验证配置。先在自己的服务器上写个获取数据…

微信地图 leaflet 腾讯地图

本来在微信项目中使用的高德地图&#xff0c;发现不是想象中的好用&#xff0c;而且用了微信&#xff0c;感觉使用腾讯地图会比较方便&#xff0c;所以&#xff0c;索性使用leaflet腾讯地图的底图来实现。 其中关于正确使用腾讯地图参考了https://github.com/wuxiashuangji/TX…

微信地图组件小程序报错“permission“

报错原因 地图可以任意添加&#xff0c;但用户的位置属于个人隐私&#xff0c;因此需要添加服务引导程序&#xff0c;告知用户地理位置的获取。需要添加 Permission &#xff08;小程序权限获取设置&#xff09;。 解决方法 该片段用于获取位置权限&#xff0c;注意该片段如…

uniapp 微信对接地图的三种操作

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 1.uni.getLocation 获取当前经维度 先上代码 let that this// 获取用户是否开启 授权获取当前的地理位置、速度的权限。uni.getSetting({success (res) {console.log(res)// 如果没有授权if (!res.au…