文章目录
- 套接字相关接口
- (一)创建套接字socket
- (二)套接字地址
- (三)命名套接字bind
- (四)创建监听队列(套接字队列)listen
- (五)接收连接accept
- (六)请求连接connect
- (七)关闭套接字
套接字相关接口
(一)创建套接字socket
- socket系统调用创建一个套接字并返回一个文件描述符,使用该文件描述符可以访问该套接字。
- 头文件:
sys/types.h
sys/socket.h
int socket(int domain, int type, int protocol);
- domain : 指定协议族
域 | 说明 |
---|---|
AF_UNIX | UNIX域协议(文件系统套接字) |
AF_INET | ARPA因特网协议(UNIX网络套接字) |
AF_ISO | ISO标准协议 |
AF_NS | 施乐(Xerox)网络系统协议 |
AF_IPX | Novell IPX协议 |
AF_APPLETALK | Appletalk DDS |
-
type : 取值包括
SOCK_STREAM
、SOCK_DGRAM
- SOCK_STREAM有序可靠的面向连接的双向字节流、对于AF_INET域套接字来说,默认是通过TCP连接进行双向传递,TCP协议提供的分片和重组长消息,重传网络中丢失的数据
- SOCK_DGRAM数据报服务,发送最大长度(固定)的消息,无法保证乱序的情况,对于AF_INET域来说,默认是UDP数据报提供
-
protocol : 一般由套接字域和套接字类型来与决定
- 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);
- 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调用失败
(七)关闭套接字
- 类似于文件描述符,打开一个文件,使用完毕后,必须要关闭文件描述符,close函数来中止连接,服务器和客户端都因该关闭;
- 对于服务器来说,read返回0时(
说明客户端关闭了连接
),关闭客户端的套接字
注意:
- 若套接字是面向连接的,并设置了SOCK_LINGER选项,close调用会该套接字还有数据传输时阻塞