【Linux】套接字相关接口详解

套接字相关接口

(一)创建套接字socket

  • socket系统调用创建一个套接字并返回一个文件描述符,使用该文件描述符可以访问该套接字。
  • 头文件:sys/types.h sys/socket.h

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

  • domain : 指定协议族
domain协议族 说明
AF_UNIX UNIX域协议(文件系统套接字)
AF_INET ARPA因特网协议(UNIX网络套接字)
AF_ISO ISO标准协议
AF_NS 施乐(Xerox)网络系统协议
AF_IPX Novell IPX协议
AF_APPLETALK Appletalk DDS
  • type : 取值包括SOCK_STREAMSOCK_DGRAM

    • SOCK_STREAM有序可靠的面向连接的双向字节流、对于AF_INET域套接字来说,默认是通过TCP连接进行双向传递,TCP协议提供的分片和重组长消息,重传网络中丢失的数据
    • SOCK_DGRAM数据报服务,发送最大长度(固定)的消息,无法保证乱序的情况,对于AF_INET域来说,默认是UDP数据报提供
  • protocol : 一般由套接字domain协议族和套接字type类型来与决定

    • 0为默认协议
  • 返回值:成功返回一个文件描述符,失败-1


(二)套接字地址

  • AF_UNIX域套接字地址结构体
    头文件sys/un.h
struct sockaddr_un
{
    
    
	sa_family_t sum_family;		//AF_UNIX(short int 类型、sys/un.h中声明)
	char 		sun_path[];		//路径套接字文件名
};
  • AF_INET域套接字的地址结构体
    头文件:
    netinet/in.h
struct sockaddr_in
{
    
    
	short int 			sin_family;	//AF_INET
	unsigned short int 	sin_port;	//端口号
	struct in_addr 		sin_addr;	//ip网络地址结构体
};

IP地址结构:

struct in_addr
{
    
    
	unsigned long int s_addr;	//4字节,32位的值
};

(三)命名套接字bind

bind系统调用把参数address中的地址分配给文件描述符sokcet关联的未命名套接字
bind调用需要将一个特定的地址结构指针转换为指向通用地址类型struct sockaddr*
int bind(int socket, const struct sockaddr* address, size_t address_len);
返回值:成功0,失败-1并设置errno错误码

errno值 说明
EBADF 文件描述符无效
ENOTSOCK 文件描述符对应的不是套接字
EINVAL 文件描述符对应的套接字已被命名
EADDRNOTAVAIL 地址不可用
EADDRINUSE 地址已经绑定一个套接字

AF_UNIX域其他的错误码

errno值 说明
EACCESS 权限不足,无法创建文件系统的路径文件名
ENOTDIR、ENAMETOOLONG 文件名不符合要求

(四)创建监听队列(套接字队列)listen

为了套接字能够接受进入的连接,服务器必须创建一个队列来保存未处理的连接请求。
int listen(int socket, int backlog);

  • backlog : 监听队列的长度,常用数值5;(当监听队列中的连接请求大于这个数时,后面的请求将会被拒绝)
  • 返回值:成功0,失败-1。errno值EBADF、EINVAL、ENOTSOCK与bind的错误代码含义相同

(五)接收连接accept

使用accept来接收监听队列中的客户端对该套接字的连接请求(当监听队列为空,没有客户端的连接请求时,该方法会阻塞block
int accept(int socket, struct sockaddr* address, size_t* address_len);

扫描二维码关注公众号,回复: 13534924 查看本文章
  • address : 该指针指向一个保存客户端地址的结构体变量中,若不需要客户端的地址信息,可以置为NULL
  • address_len :指定客户端的结构长度,超过这个值将会被截断
  • 返回值:成功返回新套接字文件描述符,监听队列没有未处理的请求时,将会阻塞block;

int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK | flags);
可以修改套接字,设置O_NONBLOCK标志(非阻塞),实现发生错误accept返回-1
错误情况大部分与bind、listen类似,EWOULDBLOCK(没有未处理链接时的错误)和EINTR(accept阻塞时,执行被中断而产生的错误)


(六)请求连接connect

客户端通过在一个未命名的套接字和服务器监听套接字之间建立连接的方法连接到服务器。

(个人理解:用一个未命名的套接字去连接指定的套接字,类似于你打电话给你的好朋友,你的好朋友在看着电话等着你打给他,你首先得有电话,再知道对方的电话号码,这里的socket就是你的电话,address就是对方的号码,而connect就是拨打电话的过程)

int connect(int socket, const struct sockaddr* address, size_t address_len);

  • socket : 通过socket系统调用创建的未命名套接字
  • address : 指定服务器的套接字的地址信息
  • 返回值:成功0,失败-1并设置errno
errno值 说明
EBADF 传递给socket参数的文件描述符无效
EALREADY 该套接字已有正在进行的连接
ETIMEDOUT 连接超时
ECONNREFUSED 连接被拒绝

注意:

  • 连接没有立马建立,将会被阻塞一段时间
  • 超时时间到达,连接被放弃,connect调用失败
    在这里插入图片描述

(七)关闭套接字

头文件:unistd.h
int close(int fd);

  • 类似于文件描述符,打开一个文件,使用完毕后,必须要关闭文件描述符,close系统调用并非真正的关闭一个连接,而是将fd的引用计数-1,当fd的引用计数为0时,才真正的关闭该连接。
  • 在多进程程序中,一次fork调用默认将父进程中打开的socket的引用计数+1,因此必须在父子进程都对fd描述符关闭,才能真正关闭连接
  • 对于服务器来说,read返回0时(说明客户端关闭了连接),关闭客户端的套接字

注意:

  • 若套接字是面向连接的,并设置了SOCK_LINGER选项,close调用会该套接字还有数据传输时阻塞

拓展:若不考虑引用计数,而直接关闭该链接,则使用shutdown系统调用;
#include <sys/socket.h>
int shutdown(int sockfd, int howto);

  • sockfd: 要终止的描述符
  • howto:shutdown的行为
  • 返回值:成功0,失败-1并设置errno
howto可选值 含义
SHUT_RD 关闭sockfd读的权限,sockfd接收缓冲区的数据被丢弃,不能再对sockfd执行读操作
SHUT_WR 关闭sockfd写的权限,sockfd的发送缓冲区中数据会在关闭连接之前全部把数据发送出去,应用程序不可对sockfd文件描述符执行写操作,连接处于半关闭状态
SHUT_RDWR 同时关闭sockfd的读和写

猜你喜欢

转载自blog.csdn.net/xiaoxiaoguailou/article/details/121569945
今日推荐