Socket通信过程
(嘘~,偷来的图)
客户端
- 调用socket()函数创建套接字
- 调用connect()函数连接服务端
- 调用write()/read()函数和send()/recv()函数进行数据的收发
- 调用close()函数关闭socket
服务器端
- 调用socket()函数创建套接字,再用bind()函数将创建的套接字与服务器端IP地址绑定
- 调用listen()函数监听socket()函数创建的套接字,等待客户端的连接请求
- 调用accept()函数接收连接请求,返回一个对应于此连接的新的套接字,用于通信
- 调用write()/read()函数和send()/recv()函数进行数据的读写,通过accept()函数返回的套接字和客户端进行通信
- 调用close()函数关闭socket
Socket 函数介绍
socket()
int socket(int domain, int type, int protocol);
描述:用于创建一个套接字描述符。
返回值:成功时返回一个全新的文件描述符,失败时返回-1。
参数:
- domain: 即协议域,又称为协议族(family),默认选择AF_INET
类型 | 说明 |
AF_INET | IPv4网络通信 |
AF_INET6 | IPv6网络通信 |
AF_PACKET | 链路层通信 |
AF_UNIX, AF_LOCAL | 本地通信 |
2. type:数据传输方式/套接字类型
类型 | 说明 |
SOCK_STREAM | 字节流套接字 |
SOCK_DGRAM | 数据报套接字 |
SOCK_SEQPACKET | 有序分组套接字 |
SOCK_RAW | 原始套接字 |
3. type:表示传输协议,可设置为0,表示选择当前family和type组合下的系统 默认值
类型 | 说明 |
IPPROTO_TCP | TCP传输协议 |
IPPTOTO_UDP | UDP传输协议 |
IPPROTO_SCTP | STCP传输协议 |
IPPROTO_TIPCTCP | TIPC传输协议 |
注意:参数中type和protocol并不能随意组合。
bind()
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
描述:用于服务器端,为套接字绑定网络地址和端口号。可以理解为我们调用一个socket()创建一个socket时,返回的socket描述字存在于协议族空间中,但没有具体的地址。如果想要给它一个地址,就需要调用bind()函数。如果只想使用connect()则不需要调用,因为当使用connect()函数调用,它会检查socket是否已经绑定,如果没有,它会分配一个空闲的端口。
返回值:成功返回0,否则返回-1,并设置错误码。
参数:
- sockfd:需要绑定的套接字文件描述符,由socket()函数创建的,唯一标识一个socket
- addr:指向特定协议的地址结构的指针,地址结构根据地址创建socket时的地址协议族不同而不同
- addrlen:对应的地址长度
listen()
int listen(int sockfd, int backlog);
描述:将一个套接字描述符设为监听套接字(主动转为被动描述符),使其能够自动接收到来的连接,并为连接队列指定一个长度限制。
返回值:成功返回0,否则返回-1,并设置错误码。
参数:
- sockfd:需要绑定的套接字文件描述符,由socket()函数创建的,唯一标识一个socket
- backlog:设置连接队列的长度
补充:backlog参数详解
connect()
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
描述:让目标套接字与指定的网络地址和端口号连接。
返回值:成功返回0,否则返回-1,并设置错误码。
参数:
- sockfd:需要绑定的套接字文件描述符,由socket()函数创建的,唯一标识一个socket
- addr:指向特定协议的地址结构的指针,地址结构根据地址创建socket时的地址协议族不同而不同(一般是服务器端的协议地址)
- addrlen:对应的地址长度
accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
描述:被动监听客户端发起的tcp连接请求,三次握手后连接建立成功。
返回值:成功返回一个套接字文件描述符,专门用于与连接成功的客户端进行通信。否则返回-1,并设置错误码。
参数:
- sockfd:需要绑定的套接字文件描述符,由socket()函数创建的,唯一标识一个socket
- addr:指向特定协议的地址结构的指针,地址结构根据地址创建socket时的地址协议族不同而不同(一般是客户端的协议地址)
- addrlen:对应的地址长度
write()
#include<unistd.h>
ssize_t write(int fd,const void*buf,size_t count);
描述:用于往文件描述符对应的buffer写数据。
返回值:成功返回写入的字节数,否则返回-1,并设置错误码。
参数:
- fd:accept()函数返回的用于连接套接字文字描述符
- buf:待发送的数据的缓冲区
- count:缓冲区大小
read()
#include<unistd.h>
ssize_t write(int fd,const void*buf,size_t count);
描述:用于从文件描述符对应的buffer读取数据。
返回值:成功返回读出的字节数,否则返回-1,并设置错误码。
参数:
- fd:accept()函数返回的用于连接套接字文字描述符
- buf:接受到的数据的缓冲区
- count:缓冲区长度
send()
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
描述:向tcp连接的另一端发送数据。
返回值:成功时返回发送的字符数,否则返回-1,并设置错误码。
参数:
- sockfd:accept()函数返回的用于连接套接字文字描述符
- buf:待发送的数据的缓冲区
- len:缓冲区长度
- flags:调用方式标志位,一般为0,改变flags将改变send发送的形式
recv()
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
描述:从tcp连接的另一端接收数据。
返回值:成功时返回接收的字符数,否则返回-1,并设置错误码。
参数:
- sockfd:accept()函数返回的用于连接套接字文字描述符
- buf:接受到的数据的缓冲区
- len:缓冲区长度
- flags:调用方式标志位,一般为0,改变flags将改变recv接收的形式
类型 | 说明 |
MSG_DONTROUTE | 不查找表 |
MSG_OOB | 接受或者发送带外数据 |
MSG_PEEK | 表示只是从系统缓冲区中读取内容,而不清除系统缓冲区的内容 |
MSG_WAITALL | 表示等到所有的信息到达时才返回 |