socket编程接口(通用:创建和绑定套接字),udp协议的收发数据接口,tcp协议的建立连接+收发数据接口,端口号和ip地址的网络和本地类型相互转换(模拟实现思路+接口),inet_ntoa覆盖问题

目录

socket编程接口

通用

socket()

函数原型

domain

type

protocol

返回值

bind()

函数原型

​编辑

socket

address

address_len

返回值

close()

函数原型

​编辑

返回值

udp协议的收发

recvfrom() 

函数原型

​编辑

sockfd

buf , len

flags 

src_addr , addrlen

返回值

sendto

函数原型

sockfd

buf , len

flags

dest_addr , addrlen

返回值

tcp协议的建立联系

listen

函数原型

sockfd

backlog 

返回值

accept

函数原型

sockfd

addr

addrlen 

返回值

connect

函数原型

sockfd

addr

addrlen 

返回值

tcp协议的收发

文件io接口

recv

函数原型

前三个参数

flags

返回值 

send 

函数原型

前三个参数

flags

 返回值 

数据转换函数

网络字节序和主机字节序的转换(端口号)

自己实现

接口

字符串和整数类型的转换(ip地址)

自己实现

字符串转整数

整数转字符串

注意点

注意点


sockaddr结构体介绍 --  套接字介绍,sockaddr结构(为什么要有,sockaddr_in和sockaddr_un的介绍+参数),ifconfig命令(本地环回地址)-CSDN博客

socket编程接口

通用

socket()

函数原型

创建套接字

  • tcp/udp协议均适用
domain
  • 确定套接字使用的协议家族(网络协议/本地通信)
  • 可以是AF_INET,AF_INET6,AF_UNIX(在前面讲sockaddr结构中有介绍)
type
  • 确定套接字类型(流式/用户数据报)
  • SOCK_STREAM(tcp协议) 或 SOCK_DGRAM(udp协议)
protocol
  • 一般为0即可
  • 前两个参数已经可以明确该套接字提供什么服务
返回值

返回新套接字的文件描述符

  • 也就是说,其实我们创建套接字,就是创建了个文件
  • 只不过,之前的文件指向的是显示器/磁盘/键盘等设备,这里的文件指向网卡

之后进行操作时,参数都必须带上这个返回值

  • 就相当于创建文件后返回了文件描述符fd,之后的io等操作都需要带上这个fd
  • 所以,该返回值可以叫做网络文件描述符

如果创建失败,返回-1,并设置errno

bind()

函数原型

将一个套接字与特定的地址(IP地址和端口号)关联起来

  • 通常在服务器端使用,用于指定服务器应该监听哪个地址和端口
  • tcp/udp协议均适用
socket

要绑定的套接字的文件描述符

address

包含地址信息的结构体指针

address_len

结构体的长度

返回值
  • 如果成功,返回0
  • 失败,返回-1,且设置错误码

close()

函数原型

关闭文件描述符(在之前的文件io中也使用过)

返回值
  • 0表示成功关闭
  • -1为关闭失败

udp协议的收发

recvfrom() 

函数原型

用于接收数据

sockfd

指定使用哪个套接字接收数据

buf , len

接收数据的缓冲区地址和缓冲区大小

flags 

指定接收数据的附加选项,通常为0

src_addr , addrlen
  • 两个输出型参数
  • src_addr 存放发送端的地址信息(用于指导响应数据的发送位置)
  • addrlen存放发送端地址信息(也就是那个结构体)的长度
返回值
  • 成功,返回接收到的数据的字节数
  • 失败,返回-1,并设置错误码

sendto

函数原型

向指定的目标地址发送UDP数据报

sockfd

指定用于发送数据的套接字文件描述符

buf , len

要发送数据的缓冲区的指针,发送数据的长度

flags

指定发送数据的附加选项,通常为0

dest_addr , addrlen
  • 传入数据报的目的地址信息(一个结构体指针)
  • 结构体的长度
返回值
  • 成功,返回发送数据的字节数
  • 失败,返回-1,并设置错误码

tcp协议的建立联系

tcp协议是面向连接的,客户端在与它通信前,需要先建立连接

listen

函数原型

在套接字上开始监听传入的连接请求(服务端使用)

sockfd

要开始监听的套接字文件描述符

backlog 

指定了在内核中等待接受连接的队列的最大长度

返回值
  • 如果成功,返回0
  • 失败,返回-1,且设置错误码

accept

函数原型

阻塞式获取连接+连接方信息(一般是服务端使用)

  • 它会从挂起的连接队列中接受一个连接,并创建一个新的套接字来处理该连接
sockfd

正在监听的套接字文件描述符

addr

(和udp中使用的recvfrom的参数一样,输出型参数)

用于存储连接方的地址信息

addrlen 

addr的大小(同上)

返回值
  • 如果成功,返回一个新的套接字文件描述符,用于之后和连接方的通信
  • 如果错误,返回-1,并设置errno

connect

函数原型

将客户端的套接字连接到服务器端的套接字,以便在它们之间进行通信(一般用于客户端)

sockfd

客户端的套接字文件描述符

addr

包含要连接的远程服务器的地址信息

addrlen 

addr的大小

返回值
  • 如果成功,返回0
  • 失败,返回-1,且设置错误码

tcp协议的收发

文件io接口

tcp是面向字节流的,其收发数据可以使用文件接口

  • 提到字节流,我们应该会想起管道文件以读/写方式打开的普通文件都是面向字节流的
  • 而他们都使用的是文件io接口
  • 所以,这里网络数据的io也可以用文件接口(也就是read和write)进行
  • 注意,在这两个函数中使用的文件描述符,应该是connect函数的返回值(这个用于实际通信),而不是socket函数的返回值(这个只用于建立连接) 

recv

函数原型

用于从套接字接收数据

前三个参数

和read中的参数作用相同

flags

可选的标志参数,用于控制接收操作的行为

  • 如果为0,和read功能相同
返回值 

和read一样

send 

函数原型

前三个参数

和write中的参数作用相同

flags

可选的标志参数,用于控制发送操作的行为

  • 如果为0,和write功能相同
 返回值 

数据转换函数

除了这些,还有一些辅助函数,帮助我们进行一些数据的转换

网络字节序和主机字节序的转换(端口号)

自己实现

其实就是调整赋值的顺序

先明确两个前提:

  • 我们的大小端顺序是以字节为单位的
  • 一般我们的端口号是16位的

我们将它拆成2个部分,每个部分8个bit:

  • x & 0xFF00 取到原来的高8位
  • x & 0x00FF 取到原来的低8位

然后就可以开始拼接了(part1 part2):

  • 如果part2=高8位,就是大端(小地址放大权重)
  • 反过来,part2=低8位,就是小端(小地址放小权重)

接口

一般我们的端口号是16位的,但在某些特殊情况下,也可能会出现32位的端口号,所以有两种接口:

字符串和整数类型的转换(ip地址)

自己实现

首先明确:

  • 字符串形式的ip地址 -- "xxx.xxx.xxx.xxx"
  • 整数形式的ip地址 -- 32位整数

所以我们可以定义一个结构体,存储ip地址的4个部分(按照.分隔,它每个部分都是8bit大小):

字符串 -> 整数

  • 使用substr函数,将它分为4个子串
  • 然后将其分别赋值给结构体的4个成员,注意:
  • part1是最先定义的,所以按照栈的结构特点,它是低地址;而最后定义的part4是高地址
  • 所以让part1=子串1(这样符合大端的高位放在低地址)
  • 依次赋值后,将结构体类型转换为32位整数即可

整数->字符串

  • 将整数类型强转为结构体类型,这样自动就可以将它分为4部分
  • 然后拼接在一起就行:

n的含义 -- network

字符串转整数

cp

  • 传入的IP地址字符串

inp

  • 输出型参数
  • 将转换后的ip地址赋值进结构体中

af

  • 用于指定地址的类型
  • AF_INET 或 AF_INET6

src

  • 要转换的字符串类型的ip地址的指针

dst

  • 指向用于存储转换后的二进制格式地址的缓冲区的指针
  • 比如 in_addr结构体的指针

cp

  • 要转换的ip地址

结果以返回值的形式获得

整数转字符串

将IPv4地址从二进制格式转换为点分十进制的字符串表示形式

in

  • 存放ip地址的结构体

字符串结果以返回值的形式给出

注意点

这个函数返回的是字符串的起始地址

  • 说明它帮助我们在内部创建好了字符串 -> 这块存放字符串的空间,即使函数结束也没有被销毁
  • 而且这个指针不需要我们手动释放(仔细想想,介绍这个函数的时候,完全没提到我们该这样)
  • 所以,这个字符串的空间是静态分配的,他存放在全局区
  • 所以它的值在main函数之前就已经确定好了
  • 那么就会导致,这块区域会被重复使用,他的值会被更新为最后一次调用它时转换成的字符串
  • 所以,如果我们需要存放多个ip地址,就不能使用这个函数,他会让最后一次的值覆盖掉前面的数据 / 如果一定要使用它,可以每次复制一下返回的字符串,让它在栈区/堆区存在一份

将IPv4或IPv6地址从二进制格式转换为字符串形式

af

  • 用于指定地址的类型
  • AF_INET 或 AF_INET6

src

  • 包含二进制格式的ip地址的指针
  • 比如 in_addr结构体的指针

dst

  • 存储结果的缓冲区的指针

size

  • 缓冲区的大小
注意点

这个函数所用的字符串缓冲区是用户传入的,就可以有效避免ntoa函数的覆盖问题 

  • 36
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值