Socket的学习(一)什么是Socket?

article/2025/10/7 20:24:34

本文参考的是《Socket通信原理》https://www.cnblogs.com/wangcq/p/3520400.html

一、TCP/IP UDP是什么?

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。下面是他们三者的关系:
socket1

可以看出TCP/IP协议族包括运输层、网络层、链路层。socket是一个接口,在用户进程与TCP/IP协议之间充当中间人,完成TCP/IP协议的书写,用户只需理解接口即可。
socket2

二、socket与TCP/IP的对应关系

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

socket3

原作者将socket通信类比为打电话这一生活场景。这里我把TCP服务器比作政府某一服务部门能,TCP客户端比作企业中某一部门电话,描述这一过程,恰好就像是socket通信,服务部门提供服务,企业部门申请服务。
要实现通信,首先政府部门都必须申请一个电话(socket_fd),并向有关部门注册(我们的系统),提供地址(sockadrr)以及属于哪个部门的(port),录入系统后,就算是合约生效了(bind),于是乎,政府广而告之,这个服务热线就算开通了,在部门里面的人员所需要做的事情,就是等待企业家拨打热线(listen)。
企业家拨打电话对地点和部门没有这么多的要求了,他并不需要绑定地址和部门,在任何一个可以拨打电话的地方(可能是同个部门,也可以同公司不同部门,甚至可能是竞争对手),他只需要拿起一个已经注册的电话(socket_fd),拨打电话(connect)
政府部门接通电话(accept)后,桥梁就打通了(服务者client_fd、顾客server_fd),可以进行听说了(read write)。企业家咨询完成(close),政府到点下班关闭服务(close)

三、socket API 简单介绍

3.1 socket() 创建socket描述符

int socket(int domain, int type, int protocol); 
//成功返回非负描述符,失败返回-1

domain:即协议域,又称为协议族(family)。
常用的地址族有:

  • AF_INET
  • AF_INET6
  • AF_LOCAL(AF_UNIX,本地通信用)
  • AF_ROUTE

协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

type:信息传送方式。

  • SOCK_STREAM
  • SOCK_DGRAM
  • SOCK_RAW
  • SOCK_PACKET
  • SOCK_SEQPACKET

protocol:对应协议。

  • IPPROTO_TCP TCP传输协议
  • IPPROTO_UDP UDP传输协议
  • IPPROTO_SCTP STCP传输协议
  • IPPROTO_TIPCTIPC传输协议
    通常设置为0,让其自动匹配。

我的理解就是:
domain 网络层相关协议 type 信息传送方式 protocol 运输层相关协议,如果前两个都确定了,系统就可以自动选择协议了。

3.2 bind()绑定实际地址

int bind(int sockfd, const struct sockaddr *addr, socklen_t
addrlen); 
//返回值:成功则为0,失败为-1

sockfd 一般服务端才需要绑定,客户端由系统内核解决
addr 所有协议都有一个公共的结构叫做const struct sockaddr,不同协议对应不同的具体结构,结构如下:

struct sockaddr {  sa_family_t sin_family;//地址族char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               }; 

可以看出,我们端口和目标地址放在同一数组中,不太容易使用。对于不同的协议,我们会通过另一种特定的结构体的来完成初始化,再通过强制类型转换,来使用bind函数。

强制转换第二个地址参数为const sockaddr *

(const sockaddr *)sockaddr_in;
(const sockaddr *)sockaddr_in6;
(const sockaddr *)sockaddr_un;
  • ipv4结构体
struct sockaddr_in {sa_family_t    sin_family; in_port_t      sin_port;   //typedef	__uint16_t		in_port_t;struct in_addr sin_addr;   
};struct in_addr {uint32_t       s_addr;     
};
  • ipv6结构体
struct sockaddr_in6 { sa_family_t     sin6_family;    in_port_t       sin6_port;      uint32_t        sin6_flowinfo;  struct in6_addr sin6_addr;      uint32_t        sin6_scope_id;  
};struct in6_addr { unsigned char   s6_addr[16];    
};
  • Unix域结构体
#define UNIX_PATH_MAX    108struct sockaddr_un { sa_family_t sun_family;                char        sun_path[UNIX_PATH_MAX];   
};
  • addrlen:协议结构体大小
    通常使用sizeof运算符计算
sizeof(sockaddr_in);//IPv4 in:internet
sizeof(sockaddr_in6);//IPv6
sizeof(sockaddr_un);//本地 un:unix

3.3 listen()、connect() 主机监听、从机链接

int listen(int sockfd, int backlog);
//返回值:成功则为0,失败为-1 
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//返回值:成功则为0,失败为-1 

listen决定需要开启的部门热线,connect拨打电话。

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

3.4 accept 建立链接

只要服务端建立链接,我们就可以进行操作了

int accept(int sockfd, struct sockaddr *addr, socklen_t  *addrlen);
//返回值:成功则为0,失败为-1 

第一个参数为服务器的socket描述字,
第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址
第三个参数为协议地址的长度。

如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。后面的读写操作都是根据这个返回值来完成的。

3.5 read和write函数,读写

这不是属于socket的API,但是socket总是伴随着以下函数:

ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, 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 recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的,如果是ECONNREST表示网络连接出了问题。

write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节 数。失败时返回-1,并设置errno变量。在网络程序中,当我们向套接字文件描述符写时有俩种可能。1)write的返回值大于0,表示写了部分或者是 全部的数据。2)返回的值小于0,此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示 网络连接出现了问题(对方已经关闭了连接)。

3.6 close关闭服务

int close(int fd);
//返回值:成功则为0,失败为-1 

close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。

注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。


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

相关文章

整数划分(递归方法)

最近讲到了递归,老师布置了一道经典的整数划分问题,浏览了网上很多代码,还是似懂非懂,想找张清晰地展现递归过程的图片也没有,今天想了想,自己画了一张才发现,想完整清晰地表现这个过程确实真的…

递归算法--整数划分

何为整数划分: 所谓整数划分,是指把一个正整数n写成为 其中, 为正整数,并且 ; 为n的一个划分。 如果 中的最大值不超过m,即 ,则称它属于n的一个m划分。 例如:6的划分: 6…

递归实现整数划分

递归思想 递归是算法设计中的一种基本而重要的算法。递归方法通过函数调用自身将问题转化为本质相同但规模较小的子问题,是分治策略的具体体现。 不多废话,直接上故事 ->从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故…

复杂的整数划分

复杂的整数划分 又到了动态规划的时间了! 记得我之前讲过的三要素哦 下面这一条题目其实思路并不是非常的难,但是在细节处理上要非常仔细,而且它有3个相互独立的动态规划问题。 总时间限制: 200ms 内存限制: 65536kB 描述 将正整数n 表…

整数划分(DP)

一个正整数 n 可以表示成若干个正整数之和,形如:nn1n2…nk,其中 n1≥n2≥…≥nk,k≥1。 我们将这样的一种表示称为正整数 n 的一种划分。 现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。 输入格式 共一行&#x…

【算法】整数划分问题

描述 整数划分问题是算法中的一个经典命题之一。把一个正整数n表示成一系列正整数之和: 正整数n的这种表示称为正整数n的划分。正整数n的不同划分个数称为正整数n的划分数,记作P(n) 。 正整数6有如下11种不同的划分,所以P(6)11。 6 51 42, …

【递归】整数划分(C++)

一、什么是整数划分 所谓整数划分,是指把一个正整数n写成如下形式: n m 1 m 2 ⋅ ⋅ ⋅ m i nm_1m_2m_i nm1​m2​⋅⋅⋅mi​; 其中 m i m_i mi​为正整数,并且 1 ≤ m i ≤ n 1 \leq m_i \leq n 1≤mi​≤n,则 { …

整数划分问题的递归解决(详解)

整数划分问题 这个问题在网上其实有好多博客、文章,本人认为讲的都稍有粗略,这篇文章是个人写的认为稍微详细一点的!! 将正整数n表示为一系列正整数之和, nn1n2n3n4......nk (其中,n1>n2&…

整数划分算法

整数划分问题 问题阐述 将正整数n表示成一系列正整数之和:nn1n2…nk, 其中n1≥n2≥…≥nk≥1,k≥1。 正整数n的这种表示称为正整数n的划分。 输入:一个正整数n 输出:n不同划分个数以及n的划分结果。 问题实例 …

整数划分总结

博客原地址:https://blog.csdn.net/dacc123/article/details/50664738 整数划分问题: 笼统上说就是将一个整数划分成若干个整数之和的方案数。整数划分有很多不同的问法,也有比较隐晦的问法。比如n个苹果放到m个盘子里,比如n个砖块…

整数划分问题(分治算法经典)

题目描述: 整数划分问题是将一个正整数n拆成一组数连加并等于n的形式,且这组数中的最大加数不大于n。 即:nn1n2…nk; n1>n2>n3…>nk 如整数的6划分为: 6 5 1 4 2, 4 1 1 3 3, 3 2 1, 3 1 1 1 2 2 2, 2 2 1 1, 2 1 …

数据源:SHP数据下载平台

1. 地理信息专业知识服务系统 中国工程院 中国工程科技知识中心 2. 国家基础地理信息中心 自然资源部 国家基础地理信息中心 3. 天地图API 自然资源部 国家基础地理信息中心 4. 中国科技资源共享网 科技部 国家科技资源共享服务工程技术研究中心 5. 地球大数据科学工…

使用ARCGIS对shp数据添加投影坐标系

系统工具箱→data management tool→投影和变换→定义投影 输入需要添加投影的shp 选择需要的投影坐标系

【使用QGIS入库将shp数据导入postgis、postgres数据库】

使用QGIS入库将shp数据导入postgis、postgres数据库 第一步,安装并打开QGIS软件 第二步,连接PostGIS数据库 在弹出的连接信息界面中配置数据库连接参数 输入数据库连接参数后点击ok 数据库连接成功则自动保存配置信息 第三步,打开数据导入…

2.1.2Arcpy开发记录_shp数据类型描述

Demo实现功能:print出输入.shp的数据类型,如线,面,点 官方文档:Describe 对象属性—ArcMap | 文档 本机环境:ArcGIS10.3,Python27 import arcpy import osfolder rE:/2021work/TJ_J/pythonT…

geotools将shp数据存入postgres

一、引入geotools的依赖 引入geotools的方法 <dependency><groupId>org.geotools</groupId><artifactId>gt-shapefile</artifactId><version>27-SNAPSHOT</version></dependency><dependency><groupId>org.geot…

全国高铁线路及站点shp数据(2020年)

名称&#xff1a;全国高铁线路及站点shp数据&#xff08;2020年&#xff09; 区域范围&#xff1a;全国 时间范围&#xff1a;2020 语言&#xff1a;中文 格式&#xff1a;.shp 该数据为2020年的全国范围的高铁线路和站点数据&#xff0c;格式为shp格式&#xff0c;坐标为wgs19…

深圳市“详规一张图”shp数据爬取后数据表无法打开的问题解决办法

最近在研究爬取深圳市规自局网站上的“详规一张图”数据&#xff0c;无奈爬虫技术太低&#xff0c;无意中看到了大佬“Atom数据”的“深圳详规“一张图”数据获取【代码更新】”一文中给出的代码爬取方案&#xff0c;再次感谢&#xff01; 然而在经历了千辛万苦之后终于将详规一…

FME将用SHP数据对栅格影像数据进行裁剪

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、需求二、实操 1.数据准备2.FME的流程设置3.裁剪的结果总结 前言 利用FME对数据进行操作与处理的过程。 一、需求 裁剪出shp范围内或者范围外的栅格影像数…

三步教你免费下载省,市,区县行政区Shp数据

摘要&#xff1a;一般非专业的GIS应用通常会用到省市等行政区区划边界空间数据做分析&#xff0c;本文简单介绍了如何在互联网上下载省&#xff0c;市&#xff0c;区县的shp格式空间边界数据&#xff0c;并介绍了一个好用的在线数据转换工具&#xff0c;并且开源。 一、首先&a…