不同协议的套接字编程(TCP套接字、UDP套接字、原始套接字等)的模型有所差异,但一般会使用到一下常用函数:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
这些函数主要作用如下:
函数名 | 说明 | 使用环境 |
---|---|---|
socket() | 根据协议类型等 创建socket(套接字编程接口) | TCP/UDP |
connect() | 主动方向被动方建立连接、会发起TCP三次握手 | 一般用于TCP |
bind() | 将socket套接字与本地协议地址绑定在一起 | TCP/UDP |
listen() | 将套接字转换为被动套接字,并制定监听的最大连接输 | TCP服务器 |
Accept() | 用于返回下一个已完成连接 | TCP服务器 |
socket-函数">socket() 函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
socket()函数用于创建套接字,socket()函数成功时返回一个类似于文件描述符的非负整数,我们称之为套接字描述符。套接字描述符 相当于一个供用户层与内核层进行通信的接口,socket()函数制定了套接字描述符的协议族、套接字类型。
- family:协议族
- type:套接字类型
- protocol:协议类型
不是所有的family和type组合都有效的,有一些组合是无效的
常用的协议族:
family | 说明 |
---|---|
AF_INET | IPv4 协议 |
AF_INET6 | IPv6协议 |
AF_LOCAL | Unix与协议 |
AF_ROUTE | 路由套接字协议 |
AF_KEY | 密钥套接字 |
socket函数的type值:
type | 说明 |
---|---|
SOCK_STREAM | 字节流套接字 |
SOCK_DGRAM | 数据报套接字 |
SOCK_SEQPAKET | 有序分组套接字 |
SOCK_RAW | 原始套接字 |
常用的protocol:
protocol | 说明 |
---|---|
IPPROTO_TCP | TCP传输协议 |
IPPROTO_UDP | UDP传输协议 |
IPPROTO_SCTP | SCTP传输协议 |
connect() 函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
connect()函数用于通信中的主动方向被动方发起建立连接的请求。对于TCP套接字来说,connect()函数会激发TCP的三次握手。
+ sockfd:套接字描述符,由socket()函数返回的。
+ addr:指向对端套接字地址结构的指针。
+ addrlen:对端套接字地址结构的大小
bind() 函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
bind()函数用于将本地协议地址与socket()函数创建的套接字绑定起来,(实际上是将本地协议地址赋予了一个套接字)。对于网际网协议来说,本地协议地址是IP地址与16bit的端口号的组合。
+ sockfd: 套接字描述符,由前面的socket()函数成功时返回
+ myaddr: 指向本地协议地址结构对象的指针
+ addrlen: 本地协议地址结构的大小。
在套接字编程中,bind()函数告诉应用程序,数据应该从哪个端口(IP地址+端口号)发送,以及应该从哪个端口接收数据。一些应用程序可能没有调用bind()函数来显示指定本地协议地址(或者只是制定了IP地址或端口号的其中一项),如TCP客户端一般在connect()之前并没有调用bind()制定本地协议地址,但是内核会为TCP客户端选择一个临时端口。 对于TCP服务器来说,一般都要制定本地协议地址,TCP服务器需要捆绑众所周知的端口,以便客户端能够对其发起通信。
listen() 函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
listen()函数仅有TCP服务器调用,主要有两个作用:
1. 将一个未连接的套接字转换为被动套接字,指示内核应该接收指向该套接字的连接请求。(socket()函数创建套接字时,默认设为主动套接字)
2. 指定内核应该为相应的套接字排队的最大连接个数。
+ sockfd: 套接字描述符,由前面的socket()函数成功时返回
+ backlog: 指定内核应该为相应的套接字排队的最大连接个数。
内核为一个给定的监听套接字维护两个队列
+ 未完成连接的队列: 服务器接受到了TCP三次握手的第一次握手,即接收到SYN分节,但三次握手还没有完成。
+ 已完成连接的队列: 三次握手已经完成,成功建立连接
* 未完成连接队列 和 已完成连接队列 的队列总数应该小与backlog*
accept() 函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept()函数有TCP服务器调用,用于返回下一个已完成连接。如果已完成连接队列为空,则阻塞。
+ sockfd: 内核创建的新的套接字描述符,用于描述与返回的客户端之间的连接
+ addr:对端进程(客户端)的协议地址
+ addrlen: 对端协议地址结构的大小。