1 socket通信流程
2 socket编程接口
Linux系统中常用的socket网络编程接口有:
- socket()
- bind()
- listen()
- accept()
- connect()
- send()
- recv()
- close()
- 其中connect()与send()为客户端专用接口;
- bind()、listen()、accept()及recv()为服务器端专用接口;
- socket()与close()则由服务器与客户端共用。
2.1 socket函数
#include <sys/socket.h>int socket(int domain, int type, int protocol);
功能:创建套接字,类似于文件操作中的open函数。
参数说明:
- domain:指定通信域,选择通信时的协议族:
– AF_INET:网络通信;
– AF_UNIX:本地通信。 - type:指定socket的连接类型,其常用取值为:
– SOCK_STREAM:TCP协议;
– SOCK_DGRAM:UDP协议;
– SOCK_RAW:ICMP协议。 - protocol:一般设置为0,表示使用默认协议。
返回值说明:
- 成功:返回一个文件描述符,之后应用程序可以采用socket通信中的读写函数在网络中收发数据;
- 失败:返回-1,并设置errno。
2.2 bind函数
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
struct sockaddr {sa_family_t sa_family;char sa_data[14]; //进程地址
};
//sockaddr的缺陷为:sa_data把目标地址和端口信息混在一起了
//sockaddr和sockaddr_in长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。
//sockaddr和sockaddr_in是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。
#include <netinet/in.h>
struct sockaddr_in {short sin_family;/*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/unsigned short sin_port;/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/ struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/ unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了跟SOCKADDR结构在内存中对齐*/
};
typedef uint32_t in_addr_t;
struct in_addr {in_addr_t s_addr;
};
功能:
使服务器端的一个socket文件与网络中的一个进程进行绑定:
- 文件描述符可标识socket文件;
- “主机名+端口号”可标识网络中的唯一进程;
- bind函数实际上是将服务器端的socket文件与网络中的进程地址进程绑定。
参数说明:
- sockfd:socket文件的文件描述符,一般由socket()函数返回;
- addr:指代服务器的通信地址,其本质为struct sockaddr结构体类型的指针;
- addrlen:参数addr的长度,实质上addr参数可接受多种协议的结构体,而这些结构体的长度各不相同,因此需使用参数addrlen额外指定结构体长度。
例如:
struct sockaddr_in servaddr; //结构体定义
bzero(&servaddr, sizeof(servaddr)); //结构体清零
servaddr.sin_family = AF_INET; //设置地址类型为AF_INET
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //设置网络地址为INADDR_ANY
servaddr.sin_port = htons(85); //设置端口号为85
返回值说明:
- 成功:返回0;
- 失败:返回-1,并设置errno。
2.3 listen函数
#include <sys/socket.h>int listen(int sockfd, int backlog);
功能:listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应该接受指向该套接字的连接请求。
参数说明:
- sockfd:socket文件描述符;
- backlog:相应套接字请求队列的最大连接个数,也就是服务器同时可建立的最大连接数量。
返回值说明:
- 成功:0;
- 失败:返回-1,并设置errno。
2.4 accept函数
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:accept函数在listen函数之后使用,其功能为阻塞等待客户端的连接请求。
当传输层使用TCP协议时,服务器与客户端在创建连接前,会先经过“三次握手”机制测试连接,“三次握手”完成后,服务器调用accept函数处理连接请求,此时若还没有客户端的请求到达,便阻塞等待调用accept函数的进程,直到接收到客户端发来的请求,且服务器中已创建的连接数未达到backlog,accept函数才会返回,并传出客户端的地址。
参数说明:
- sockfd:socket文件描述符;
- addr:传出参数,表示客户端的地址,当addr = NULL,表示不关心客户端的地址;
- addrlen:传入传出参数,传入是为函数调用提供参数addr的长度,传出时为客户端地址结构体的实际长度。
返回值说明:
- 成功:一个套接字,用于与本次通信的客户端进行数据交互;
- 失败:返回-1,并设置errno。
2.5 connect函数
#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:用于客户端,该函数的功能为向服务器发起连接请求。
- connect函数的参数与bind()函数中参数的形式一致;
- 区别在于bind中的参数为客户端进程地址,而connect的参数为服务器端地址。
参数说明:
- sockfd:socket文件描述符;
- addr:传入参数,表示要连接的服务器地址;
- addrlen:传入参数,为函数调用提供参数addr的长度。
返回值说明:
- 成功:0;
- 失败:返回-1,并设置errno。
2.6 send函数
#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:向处于连接状态的套接字中发送数据。
参数说明:
- sockfd:socket文件描述符;
- buf:指向要发送数据的缓冲区指针;
- len:缓冲区buf中数据的长度;
- flags:表示调用的执行方式(阻塞/非阻塞),通常设置为0。
// 下面的两个函数等效:
write(sockfd, buf,len);
send(sockfd, buf, len, 0);
Linux系统中还提供了sendto()函数和sendsg()函数,这两个函数不但能发送数据给已连接的套接字,还可向未连接的套接字发送数据。
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
参数说明:
- sendto函数中的前4个参数与send()函数的参数相同,之后的参数dest_addr和addrlen分别用于设置接收数据进程的地址和地址的长度;
- sendmsg函数中的第二个参数msg为struct msghdr类型的结构体指针,该参数用于传入目标进程的地址、地址的长度等信息。
返回值说明:
- 成功:0;
- 失败:返回-1,并设置errno。
2.7 recv函数
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:用于从已连接的套接字中接收信息。
此外,read()函数、recvfrom()函数和recvmsg()函数也可用于接收信息。
参数说明:
- sockfd:socket文件描述符;
- buf:指向接收数据的缓冲区指针;
- len:缓冲区buf中数据的长度;
- flags:表示调用的执行方式(阻塞/非阻塞),通常设置为0。
返回值说明:
- 成功:返回读到的字节数;
- 失败:返回-1,并设置errno。
2.8 close函数
#include <unistd.h>int close(int fd);
功能:用于释放系统分配给套接字的资源。
参数说明:
- fd:socket文件描述符;
返回值说明:
- 成功:0;
- 失败:返回-1,并设置errno。