【Linux】Socket编程基础

字节序

  • 多个字节在内存中的存放顺序,分为小端字节序和大端字节序,小端字节序时数据的低位存储在内存的低位,而大端字节序则是数据的高位存储在内存的高位。
  • 网络字节序都是大端字节序,网络通信前都要将主机字节序转化成网络字节序。

字节序转化函数

#include <arpa/inet.h> // 或者 <netinet/in.h>

// 将主机字节序转换为网络字节序(大端),32位转IP,16位转端口。
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);

// 将网络字节序转换为主机字节序
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

//将点分十进制形式的IP地址字符串转换为相应的网络字节序。
int inet_pton(int af, const char *src, void *dst);
//af: 地址族,可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。
//src: 包含IP地址的点分十进制字符串。
//dst:用于存放转换后的网络字节序二进制IP地址。
//成功转换IPv4/IPv6地址时返回1,当输入的字符串不是有效的IP地址时返回0,发生错误时返回-1。


/即将网络字节序转换为点分十进制字符串形式。
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
//af: 地址族,同样可以是AF_INET 或 AF_INET6。
//src: 指向要转换的网络字节序的指针。
//dst: 用于存放转换后字符串的缓冲区。
//size: 目标缓冲区的大小。
返回值:
//成功时返回指向转换后字符串的指针。如果发生错误(如缓冲区太小),则返回NULL。

套接字

socket通用结构体

  • sockaddr_in结构体是较为广泛使用的结构体,用于表示IPv4的网络地址信息,包括IP地址和端口号。
  • 网络通信前都要将本地字节序转化为网络字节序,接收后需要将网络字节序再转化为本地字节序。
#include <netinet/in.h>

struct sockaddr_in {
    short sin_family; // 16位地址族,对于IPv4应设为AF_INET
    unsigned short sin_port;  // 16位端口号,使用网络字节序
    struct in_addr sin_addr;   // 32位IP地址,实际上是一个in_addr结构体,其中s_addr来存放
    char sin_zero[8];  // 未使用,通常填充为0
};

//使用
struct sockaddr_in saddr;
saddr.sin_family=AF_INET;
inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr.s_addr); // 将点分十进制IP地址转换为二进制存入sin_addr
saddr.sin_port=htons(6666);// 设置端口号,使用htons转换字节序

通信类型

   通信类型控制套接字如何传输和处理数据,数据以包的形式传输

  • 连接类型/流式:确保所有包依序传输,丢包则重传
  • 数据报类型:不保证包的按序到达,可能会丢失

名空间

  • 本地名空间:套接字地址为普通地址名,使用在本地通信
  • 网络名空间:套接字地址由Internet地址和端口号(区分一台主机上多个套接字)确定,使用在网络通信

套接字函数

socket():创建套接字
  • 原型:int socket(int domain,int type,int protocal);
  • 参数:名空间、通信类型、协议
  • 名空间:AF/PF_LOCAL(本地名空间)、AF/PF_INET(网络名空间-ipv4)
  • 通信类型:SOCK_STREAM(连接类型/流式)、SOCK_DGRAM(数据报类型)
  • 协议:0,系统自动选择协议,有IPPROTO_TCP或IPPROTO_UDP
  • 返回值:套接字描 述符,失败返回-1
bind()函数:绑定服务器套接字与其地址、端口
  • 原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:sockfd为服务端创建的套接字文件描述符,addr指向一个地址结构包含服务器本身的地址以及端口号,addrlen为结构体addr的长度
listen()函数:侦听客户连接
  • 原型:int listen(int sockfd, int backlog);
  • 参数:sockfd为已绑定IP地址和端口号的套接字描述符、backlog指定有多少个挂起连接可以进入队列,超出该值的连接将被抛弃。
connect():连接服务器套接字
  • 创建两个套接字的连接,客户发起系统调用,申请与服务器建立连接
  • 原型:int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
  • 参数:sockfd为客户端创建的套接字文件描述符,addr指向一个地址结构包含服务器绑定的地址以及端口号,addrlen为结构体addr的长度
  • 返回值:0成功、-1失败
accept()函数:服务器阻塞等待接受连接,并为该连接返回一个新的套接字描述符
  • 原型:int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen);
  • 参数:sockfd为监听状态的套接字描述符、addr指向一个地址结构,用来接收客户端的地址以及端口,此端口是客户端发起连接请求时,临时分配给客户端的端口,addrlen为结构体addr长度
  • 返回值:成功返回新创建的、与客户端连接的套接字描述符,失败返回-1
  • 原先套接字文件描述符可以继续接受新连接
send()函数:发送数据
  • 用途:send() 函数用于在已连接的套接字上发送数据,常用于TCP套接字。它允许程序向网络连接的另一端发送数据。
ssize_t send(int socket, const void *buffer, size_t length, int flags);

//成功发送的字节数,如果发送失败,返回 -1。

//socket: 整型变量,表示发送数据的套接字描述符。这个描述符是由 socket() 函数创建并通过 connect() 函数(对于客户端)或者 accept() 函数(对于服务器端)准备好的。

//buffer: 指向要发送数据的缓冲区的指针。

//length: 要发送数据的字节数,以字节为单位。

//flags: 用于控制操作的标志,可以是0或以下标志的组合。常用的标志有:
/*
MSG_DONTROUTE: 不查找路由表,直接发送到本地网络接口。
MSG_OOB: 发送带外数据。
MSG_NOSIGNAL: 禁止 SIGPIPE 信号的生成,当对端关闭连接时,本端继续发送数据将不会收到这个信号,默认行为是进程会收到 SIGPIPE 信号并终止。
*/
recv()函数:接收数据
ssize_t recv(int socket, void *buffer, size_t length, int flags);

//成功时,recv() 返回实际接收到的字节数。失败返回-1

//socket: 整型变量,表示接收数据的套接字描述符。必须是通过 socket() 函数创建并经过 connect()(客户端)或 accept()(服务器端)的套接字。

//buffer: 指向缓冲区的指针。

//length: 指定缓冲区的大小。

//flags: 选项标志,用于控制接收操作的行为。常见的标志有:
/*
MSG_PEEK: 查看数据但不将其从接收缓冲区中移除,可用于非破坏性地检查数据。
MSG_DONTWAIT: 非阻塞操作,如果当前没有数据可读,立即返回,而不是阻塞等待,返回-1时有可能是因为错误也有可能是没有读到数据,可通过错误号来判断。
*/
close():释放套接字
  • int close(int fd);

补充

  • 套接字描述符实则就是一种特殊的文件描述符,所以也可以使用文件的读写操作来进行即使用read()、write(),当返回值为0时代表此时缓冲区无数据且写端关闭即断开连接。
  • 在网络通信中,通过文件描述符来发送和接收数据,实际上网络通信中的文件描述符标识的是内核中的缓冲区,分为发送缓冲区和接收缓冲区,发送方发送数据实际上是先发送到发送方的发送缓冲区,再发送到接收方的接收缓冲区,接收数据则是从接收缓冲区读取数据。
  • 阻塞模式和非阻塞模式发生在数据等待阶段,双方的区别是没有数据到来时,阻塞模式会改变进程的状态,使进程挂起成为阻塞态等待阻塞事件的结束,而非阻塞模式不会改变进程的状态,例如read()的非阻塞模式读不到数据会立刻返回,而不是阻塞等待,通常返回值为-1,并且会设置errno为EAGAIN或EWOULDBLOCK,需要通过错误码判断是发生了错误还是未读到数据,需要对事件进行循环检测。
  • 网络通信中同步异步发生在数据读写阶段,同步的意义是将数据从内核区拷贝到用户区时需要消耗用户的时间等待,而异步则是将数据从内核区拷贝到用户区时不影响用户区进程的正常运行,并在拷贝过程结束时向进程进行通知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值