客户端和服务端端口的建立与连接

2023-10-26

socket(建立通信的端口,并返回引用该端口的文件描述符).

man sockst : https://man7.org/linux/man-pages/man2/socket.2.html

头文件

#include <sys/types.h>
#include <sys/socket.h>

函数

int socket(int domain, int type, int protocol);

说明

socket()创建用于通信的端点并返回文件引用该端点的描述符。文件描述符成功调用返回的将是编号最小的文件
该进程当前未打开描述符。

参数

domain(域):

AF_INET,AF_INEF6,AF_LOCAL,AF_ROUTE

函数socket()的参数domain用于设置网络通信的域,函数socket()根据这个参数选择通信协议的族。通信协议族在文件sys/socket.h中定义。

表1 domain的值及含义

名称 含义
PF_UNIX,PF_LOCAL 本地通信
PF_X25 ITU-T X25 / ISO-8208协议
AF_INET,PF_INET IPv4 Internet协议
PF_AX25 Amateur radio AX.25
PF_INET6 IPv6 Internet协议
PF_ATMPVC 原始ATM PVC访问
PF_IPX IPX-Novell协议
PF_APPLETALK Appletalk
PF_NETLINK 内核用户界面设备
PF_PACKET 底层包访问

type(类型):

SOCK_STREAM,SOCK_DGRAM,SOCK_PACKET,SOCK_SEQPACKET

函数socket()的参数type用于设置套接字通信的类型,主要有SOCKET_STREAM(流式套接字)、SOCK——DGRAM(数据包套接字)等。

表2 type的值及含义

名称 含义
SOCK_STREAM Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
SOCK_DGRAM 支持UDP连接(无连接状态的消息)
SOCK_SEQPACKET 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出
SOCK_RAW RAW类型,提供原始网络协议访问
SOCK_RDM 提供可靠的数据报文,不过可能数据会有乱序
SOCK_PACKET 这是一个专用类型,不能呢过在通用程序中使用

并不是所有的协议族都实现了这些协议类型,例如,AF_INET协议族就没有实现SOCK_SEQPACKET协议类型。

protocol(协议)

IPPROTO_TCP, IPPROTO_UDP, IPPROTO_TIPC;一般为0

函数socket()的第3个参数protocol用于制定某个协议的特定类型,即type类型中的某个类型。通常某协议中只有一种特定类型,这样protocol参数仅能设置为0;但是有些协议有多种特定的类型,就需要设置这个参数来选择特定的类型。

类型为SOCK_STREAM的套接字表示一个双向的字节流,与管道类似。流式的套接字在进行数据收发之前必须已经连接,连接使用connect()函数进行。一旦连

接,可以使用read()或者write()函数进行数据的传输。流式通信方式保证数据不会丢失或者重复接收,当数据在一段时间内任然没有接受完毕,可以将这个连接人为已经死掉。
SOCK_DGRAM和SOCK_RAW 这个两种套接字可以使用函数sendto()来发送数据,使用recvfrom()函数接受数据,recvfrom()接受来自制定IP地址的发送方的数据。
SOCK_PACKET是一种专用的数据包,它直接从设备驱动接受数据。

errno

函数socket()并不总是执行成功,有可能会出现错误,错误的产生有多种原因,可以通过errno获得:

表3 errno的值及含义

含义
EACCES 没有权限建立制定的domain的type的socket
EAFNOSUPPORT 不支持所给的地址类型
EINVAL 不支持此协议或者协议不可用
EMFILE 进程文件表溢出
ENFILE 已经达到系统允许打开的文件数量,打开文件过多
ENOBUFS/ENOMEM 内存不足。socket只有到资源足够或者有进程释放内存
EPROTONOSUPPORT 制定的协议type在domain中不存在

示例

建立一个流式套接字:

int sock = socket(AF_INET, SOCK_STREAM, 0);

返回值

成功返回新的文件描述符, 否则返回-1;

bind()( 绑定ip和端口)

头文件

#include <sys/types.h>
#include <sys/socket.h>

函数

int bind(int sockfd, const struct sockaddr addr, socketlen_t addrlen );

说明

sockfd是调用socket返回的文件描述符

addr是指向数据结构struct sockaddr 的指针, 它保存你的地址(即端口和IP地址)信息

addrlen设置为sizeof(struct sockaddr)

返回值

出错-1,无错为0

socket 的相关结构体

#include <sys/socket.h>

struct sockaddr{

​	sa_family sin_family;

​	char sa_data[14];

};
struct sockaddr_in {

​	sa_family_t sin_family; //协议族

​	in_port_t sin_port;    //端口

​	struct in_addr sin_addr; //地址

}
struct in_addr {

​	unit32_t  s_addr;

};

用struct sockaddr_in需要强转成struct sockaddr;

本地与网络的转换

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong); //本地字节序转换成网络字节序的长整形

uint32_t htons(uint32_t hostshort); //主机字节序转换成网络字节序的短整形

uint32_t ntohl(uint32_t hostlong); //网络字节序转换成本地字节序的长整形

uint32_t ntohs(uint32_t hostshort); //网络字节序转换成本地字节序的短整形

in_addr_t inet_addr (const char *ip);//ip字符串强转成网络字节序的整数型

char *inet_ntoa(struct in_addr in);//将struct in_addr结构体输出为ip字符串

网络字节序和本地字节序不同, 因此要转换.

listen():监听socket

将主动套阶子变被动套阶字;

头文件

#include <sys/types.h>

#include <sys/socket.h>

函数

int listen(int sockfd, int backlog);

sockfd是掉用socket()返回的套接字文件描述符.

backlog是在进入队列中允许的连接数目

返回值

出错-1,设errno

accept() :(接收一个套接字中已建立的连接)

头文件

#include <sys/types.h>

#include <sys/socket.h>

函数

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept()用来从sockfd上返回一个新的链接;

1.第一个参数sockfd必须是经由socket(),bind(),listen()函数处理后的socket;
利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连

接;

2.第二个参数是一个地址,将保存对端地址到该地址中.
指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端地址)填写,返回地址addr的确切格式由套接字的

地址类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL;

	备注:addr是个指向局部数据结构sockaddr_in的指针,这就是要求接入的信息本地的套接字(地址和指针)。

3.第三个参数是地址长度的地址.

	一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值;

备注:addrlen是个局部整形变量,设置为sizeof(struct sockaddr_in)。

说明

	accept()系统调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。它提取出所监听套接字的等待连接队列中第一个连接请求,创建

一个新的套接字,并返回指向该套接字的文件描述符。新建立的套接字不在监听状态,原来所监听的套接字也不受该系统调用的影响。

	如果队列中没有等待的连接,套接字也没有被标记为Non-blocking,accept()会阻塞调用函数直到连接出现;如果套接字被标记为Non-blocking,队列中也没有

等待的连接,accept()返回错误EAGAIN或EWOULDBLOCK。

备注:一般来说,实现时accept()为阻塞函数,当监听socket调用accept()时,它先到自己的receive_buf中查看是否有连接数据包;

若有,把数据拷贝出来,删掉接收到的数据包,创建新的socket与客户发来的地址建立连接;

若没有,就阻塞等待;

备注:新建立的套接字准备发送send()和接收数据recv()。

返回值

如果成功返回一个新的sockfd,原来的sockfd依然可以用来accept,如果失败,则返回-1;

connect()

客户端主动连接服务端

头文件

	#include <sys/types.h>

	#include <sys/socket.h>

函数

	int connet(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

返回值:

	错误返回-1;否则返回0;

send()发送数据

头文件

	 #include <sys / types.h> 
	 #include <sys / socket.h>

函数

   ssize_t send(int sockfd ,const void * buf ,size_t len ,int flags );

	flags可以设置为0;

	sendto主要用在UDP通信中

	dest_addr为远端要通信的网络地址

返回值

	实际读入缓冲的数据的字节数.在出错的时候返回-1;同时设置errno

recv()(接受信息)

头文件

   #include <sys / types.h> 

   #include <sys / socket.h>

函数

   ssize_t recv(int sockfd ,void * buf ,size_t len ,int flags) ;

	sockfd是要读的套接字描述符

	flags可设置为0

返回值

  这些调用返回接收到的字节数,如果出错则返回-1。如果发生错误,则将errno设置为指示 错误。

   当流套接字对等方执行有序关闭时,返回值将为0(传统的“文件结束”返回)。
   
    各个域(例如UNIX和Internet)中的数据报套接字 域)允许使用零长度数据报。当这样的数据报是
    
   收到,返回值为0。

   如果请求的字节数为0,也可能返回值0从流套接字接收的值为0。

close()

#include <unistd.h>

int close(int fd);

getpeername()(获取对端地址)

头文件

   #include <sys / socket.h>

函数

   int getpeername(int sockfd ,struct sockaddr * addr ,socklen_t  * addrlen );

说明

getpeername()在addr指向的缓冲区中返回连接到套接字sockfd的对等方的地址。addrlen参数 应该初始化以指示所指向的空间量地址。返回时,它包含

返回名称的实际大小(用字节)。如果提供的缓冲区太小,名称将被截断。

如果提供的缓冲区也太短,返回的地址将被截断小; 在这种情况下,addrlen返回的值将大于提供给通话。

返回值

成功时,返回零。发生错误时,返回-1,而errno为设置适当。

gethostname(获取本地主机名)

int gethostname(char *hostname, size_t size);
hostname是一个字符数组指针,他将在函数返回时保存主机名.
size是hostname 的字节长度.
返回值: 函数调用成功时返回0,失败返回-1;

setsocketopt()(在套接字上获取和设置选项)

头文件

#include <sys / types.h>
#include <sys / socket.h>

函数

   int getsockopt(int sockfd ,int level ,int optname , void * optval ,socklen_t * optlen ); 
   int setsockopt(int sockfd ,int level ,int optname ,const void * optval ,socklen_t optlen );
   level:(级别): 指定选项代码的类型。
   optname(选项名): 选项名称
  optval(选项值): 是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
  optlen(选项长度) :optval 的大小

返回值

成功后,标准选项将返回零。错误时,-1. 返回,并正确设置了errno。
一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。

重启地址

int val = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,(const char*)&val, sizeof(int)) < 0) {
return -1;
}

例子

//服务端的建立sock(),setsockopt(),bind(),listen();
int socket_create(int port) {
    int sockfd;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { //int socket(int domain, int type, int protocal);
        return -1;
    }
    int val = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,(const char*)&val, sizeof(int)) < 0) {
        return -1;
    }
    struct sockaddr_in server;//创建表单名server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);//本地字节序转换成网络字节序的短整形
    server.sin_addr.s_addr = inet_addr("0.0.0.0");//所有的都要,ip地址转换成网络字符串
    if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
        return -1;
    }

    if (listen(sockfd, 10) < 0) {
        return -1;
    }
    return sockfd;
}
//客户端的建立
int socket_connect(char *ip, int port){
    int sockfd;//创建端口名
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        return -1;
    }

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);
    if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
        return -1;
    }
    return sockfd;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

客户端和服务端端口的建立与连接 的相关文章

  • texlive支持中文的简单方法

    1 确保tex文件的编码方式是UTF 8 2 在文档开始处添加一行命令即可 即 usepackage UTF8 ctex 如下所示 documentclass article usepackage UTF8 ctex begin artic
  • 文件管理系统(操作系统)——9张思维导图

    文件管理系统 1 文件管理 1 1 一个文件的逻辑结构 比如一个文本txt文件 又或者Excel文件 在我们用户看来 它是长什么样的 这个就是逻辑结构 几个概念 逻辑结构 就是指在用户看来 单个文件内部的数据应该是如何组织起来的 物理结构
  • Win11微软账号登录不上?Win11登录Microsoft账户出错的解决方法

    Win11微软账号登录不上 近期有部分Win11用户反映在登录微软账号会出现一直转圈 无法登录的情况 这样导致部分功能都不能正常使用了 为此十分令人头疼 那么对于这一情况 有没有什么方法可以有效的解决呢 下面小编教给大家操作方法 大家可以去
  • Linux系统的安装(在VM虚拟机上安装CentOS 7)

    工具准备 物理计算机一台 配置要求 操作系统 win10 64位 大家基本上都是 硬盘可用容量 20G以上 内存容量 4G以上 虚拟机安装包 VMware workstation full 12 5 下载链接 点我下载 提取码 9gha C
  • linux 如何创建卷组

    1 创建一个物理卷 Pvcreate dev sd1 dev sd2 dev sd3 dev sd4 2 用刚才创建的物理卷创建一个卷组 Vgcreate 卷组名 dev sd1 dev sd2 dev sd3 dev sd4 3 创建逻辑
  • 计算机领域中随处可见的抽象

    想要管理多种具体的东西 那么需要遵守每种东西的规范 如果想要提供一种通用模式来对这些具体的东西统一管理 需要使用一种古老的技术 抽象 抽象是将多种具体的东西 管理时需要遵守的规范 的共同点抽取出来 放入到更高一层的抽象层 在抽象层不定义或少
  • unix环境高级编程——文件IO

    本期主题 unix环境高级编程 文件IO 文件IO 0 引言 1 文件描述符 2 IO编程中常用的API接口 1 open函数 2 close函数 3 read函数 4 write函数 5 lseek函数 3 函数sync fsync和fd
  • RTX线程通信之——线程标志

    文章目录 Thread Flags 概念 RTX线程标志API 案例 LED灯同步闪亮 小结 参考资料 Thread Flags In a real application we need to be able to communicate
  • Linux 磁盘与文件系统管理(鸟哥私房菜)

    本文来自 http vbird dic ksu edu tw linux basic 0230filesystem php 第八章 Linux 磁盘与文件系统管理 系统管理员很重要的任务之一就是管理好自己的磁盘文件系统 每个分割槽不可太大也
  • 程序员的自我修养——链接、装载与库

    1 温故而知新 操作系统概念 北桥 连接高速芯片 系统调用接口 以软件中断的方式提供 如Linux使用0x80号中断作为系统调用接口 多任务系统 进程隔离 设备驱动 直接使用物理内存的弊端 地址空间不隔离 内存使用效率低 程序运行的地址不确
  • [架构之路-185]-《软考-系统分析师》-3-操作系统基本原理 - 文件索引表

    目录 一 文件的索引块 二 索引分配表 三 索引表的链接方案 四 多层索引 五 混合索引分配 一 文件的索引块 存放在目录中的文件 并非是文件的真实内容 目录中记录了文件的索引块是几号磁盘块 文件对应的索引表是存放在指定的磁盘块中的 二 索
  • 自己动手写操作系统(一)

    本系列文章将一步步实现一个简单的操作系统 实验环境是在Linux系统下通过Bochs虚拟机运行我们自己写的操作系统 一 实验环境搭建 1 Ubuntu的安装 Windows用户可以选择在虚拟机中安装Ubuntu 具体安装教程可自行搜索 2
  • Linux 内核中的 Device Mapper 机制

    Linux 内核中的 Device Mapper 机制 尹 洋 在读博士生 尹洋 中科院计算所国家高性能计算机工程技术研究中心的在读博士生 主要从事服务部署和存储资源管理以及Linux块设备一级的开发和研究工作 简介 本文结合具体代码对 L
  • 内存管理——分页分段

    一 分页存储管理 1 页面与页框 1 页面 将一个进程的逻辑地址空间分成若干个大小相等的片 称为页面或页 并为各页加以编号 2 页框 相应于页面 把内存空间分成和页面相同大小的若干个存储块 称为 物理 块或页框 frame 3 页内碎片 在
  • gdb attach 进程调试

    gdb调试正在运行的进程 GDB可以对正在执行的程序进行调度 它允许开发人员中断程序 并查看其状态 之后还能让这个程序正常地继续执行 gdb attach xxxxx xxxxx为利用ps命令获得的子进程process
  • Common块和Bss段的区别

    昨天看 程序员的自我修养 链接 装载与库 发现不是很理解为什么要用common块 然后仔细看了一番 有了自己的理解 common块 用来存放弱符号 而全局未初始化变量是弱符号 但是难道不是应该存放在 bss段吗 为什么要有common块呢
  • 《OSPF和IS-IS详解》一1.7 独立且平等

    本节书摘来自异步社区 OSPF和IS IS详解 一书中的第1章 第1 7节 作者 美 Jeff Doyle 更多章节内容可以访问云栖社区 异步社区 公众号查看 1 7 独立且平等 OSPF和IS IS详解与TCP IP相比 OSI协议对各国
  • Linux(12):磁盘配额(Quota)与进阶文件系统管理

    磁盘配额 Quota 的应用与实作 Quota 的一般用途 针对 www server 例如 每个人的网页空间的容量限制 针对 mail server 例如 每个人的邮件空间限制 针对 file server 例如 每个人最大的可用网络硬盘
  • I/O设备模型

    I O设备模型 绝大部分的嵌入式系统都包括一些I O Input Outut 输入 输出 设备 例如仪器上的数据显示屏 工业设备上的串口通信 数据采集设备上用于保存数据的Flash或SD卡 以及网络设备的以太网接口等 I O设备模型框架 R
  • 【操作系统xv6】学习记录4-一级页表与二级页表

    占位

随机推荐

  • Mac OS上使用ffmpeg的“血泪”总结

    标题真不是夸张 这几天在整理视频相关的处理流程 为了获得一些性能数据 打算在自己的MacBook Pro 上面装ffmepg 这一折腾4 5天就过去了 有些问题 在解决之后就豁然开朗了 没有解决之前 真的是百思不得其解 中间就好像隔着一层纱
  • AF_INET和AF_PACKET区别

    http blog csdn net kzm2008 article details 5372834 man 7 ip man 7 packet Packet sockets are used to receive or send raw
  • 单片机蓝桥杯——定时中断实现数码管显示、按键判断

    1 1ms定时中断T0 控制数码管显示 1 关于中断 关于定时中断的初始化函数可直接在STC ISP软件上生成 如下图所示 注意 初始化函数中并没有打开EA和ET0 需要自己加上 2 关于数码管显示 数码管段码 segCode 0 segC
  • Flutter提供者模式说明

    在本文中 我们将介绍Flutter中的Provider模式 Google的工作小组建议使用提供程序模式 他们还在Flutter的Pragmatic State Management中的 Google I O 2019上进行了介绍 其他一些模
  • Nginx的Gzip压缩

    Nginx的Gzip压缩 Nginx开启Gzip压缩功能 可以使网站的css js xml html 文件在传输时进行压缩 提高访问速度 进而优化Nginx性能 在Nginx配置文件中可以配置Gzip的使用 相关指令可以在http区域 se
  • Java流程控制--分支结构

    Java流程控制 分支结构 if 单分支 结构 if 条件表达式 这个表达式的结果是布尔值 要么是false 要么是true 如果上面 中的表达式返回结果是true 那么执行 中代码 如果上面 中的表达式返回结果是false 那么不执行 中
  • Unity的Audio组件命令有哪些

    Unity 的 Audio 组件命令有以下几种 Play 播放音频 Pause 暂停音频 UnPause 取消暂停音频 Stop 停止播放音频 SetScheduledStartTime 设置音频开始播放的时间 SetScheduledEn
  • SpringBoot使用Redisson做延迟队列案列(超详细)

    背景 有些场景下 需要延迟触发一些任务 比如 延迟几秒钟发送短信或者邮件 某些业务系统回调 需要延时几秒钟后回调 当然 实现延时触发的方式有很多 我这里采用 redisson 的 RDelayedQueue 一是因为接入简单 二是没有分布式
  • post使用form-data和x-www-form-urlencoded的本质区别

    一是数据包格式的区别 二是数据包中非ANSCII字符怎么编码 是百分号转码发送还是直接发送 一 application x www form urlencoded 1 它是post的默认格式 使用js中URLencode转码方法 包括将na
  • 修改onnx模型输出示例

    前言 如图是netron github链接 软件中打开的onnx模型 可以看到右边模型的最终输出结果是分类值predict 0而非概率值 那么如何获取中间过程的概率值 或者说怎么把右边的图砍掉一截变成左边的图呢 代码 读入模型 import
  • keras_cv进行数据增强

    使用keras cv来做分类数据增强 以下直接上流程 具体的原理和代码上github查看源码及配合tensorflow官网及keras官网来做处理 当前 2022 10 8 这些文档还不是很全 import os import numpy
  • Shell 运行shell脚本的多种方法

    详情地址 运行shell脚本的多种方法 小步教程 Shell 运行shell脚本的多种方法 运行shell脚本文件可通过两类方法 方法1 bash执行 语法 sh 文件 文件可使用相对路径或绝对路径 示例 sh 01hello sh 等价写
  • 游戏出现GetThreadContext failed报错 Unity开发

    解决方案 1 检查是否有360 有的情况 1 简单方案 卸载360 2 专业方案 将游戏exe添加到360信任名单中 解释 360会将一些模拟按键视为木马 然后游戏运行一般直接闪退 2 检查防火墙 专业方案 将游戏exe加入防火墙允许应用的
  • 多端技术栈uniapp开发优势是什么?适合哪种类型产品开发?

    uniapp是一种基于Vue js的跨平台开发框架 它可以支持以单一代码库编写多个平台的应用程序 包括iOS Android Web等 以下是uniapp开发的优势和适用类型的介绍 1 跨平台开发 相比于传统的原生开发 uniapp可以基于
  • tar 打包、压缩和备份

    如何理解 首先讲两个概念 打包 将一大堆文件或目录变成一个总的文件 压缩 将一个大的文件通过压缩算法变成一个小文件 这两种场景一定要区分开 网络上有的技术文章 将tar命令解释为压缩命令 是不完全正确的 关于此点 本文不再拓展 感兴趣的可以
  • 黄页是什么意思

    黄页 起源于北美洲 1880年世界上第一本黄页电话号簿在美国问世 至今已有100多年的历史 黄页是国际通用按企业性质和产品类别编排的工商电话号码薄 相当于一个城市或地区的工商企业的户口本 国际惯例用黄色纸张印制 故称黄页 目前我们常说的黄页
  • Python 类型提示和静态类型检查

    介绍 在本文中 将了解 Python 类型检查 Type Checking 在本教程中 将了解以下内容 类型注释和类型提示 将静态类型添加到代码中 包括你的代码和其他人的代码 运行静态类型检查器 在运行时强制类型 视频介绍如下 Python
  • 树莓派软键盘乱码

    树莓派软键盘乱码的快速处理 matchbox keyboard的显示 处理办法 matchbox keyboard的显示 正常的Matchbox keyboard安装完成后应该出现如下的界面 但是 在初次安装时 发现部分用户的界面出现乱码情
  • react,useEffect一直重复执行

    import useState useEffect from react useEffect callback arr useEffect接受两个参数 callback 回调函数 第一次会默认执行一次 内部可以return一个回调函数 当卸
  • 客户端和服务端端口的建立与连接

    socket 建立通信的端口 并返回引用该端口的文件描述符 man sockst https man7 org linux man pages man2 socket 2 html 头文件 include