1)、socket
int socket(int family, int type, int protocol);
?socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,family参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。
2)、listen
int listen(int sockfd, int backlog);
?典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。
3)、accept
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。cliaddr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区cliaddr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给cliaddr参数传NULL,表示不关心客户端的地址。
bind()函数介绍
? ? ? ?在建立套接字文件描述符成功后,需要对套接字进行地址和端口的绑定,才能进行数据的接收和发送操作。
函数原型
? ? ? ?bind()函数将长度为addlen的struct sockadd类型的参数my_addr与sockfd绑定在一起,将sockfd绑定到某个端口上,如果使用connect()函数则没有绑定的必要。绑定的函数原型如下:
#include<sys/types.h>
#include<sys/socket.h>
int?bind(int?sockfd,?const?struct?sockaddr?*my_addr,?socklen_t?addrlen);
bind()函数有3个参数。
-
第1个参数sockfd是用socket()函数创建的文件描述符。 -
第2个参数my_addr是指向一个结构为sockaddr参数的指针,sockaddr中包含了地址、端口和IP地址的信息。在进行地址绑定的时候,需要弦将地址结构中的IP地址、端口、类型等结构struct sockaddr中的域进行设置之后才能进行绑定,这样进行绑定后才能将套接字文件描述符与地址等接合在一起。 -
第3个参数addrlen是my_addr结构的长度,可以设置成sizeof(struct sockaddr)。使用sizeof(struct sockaddr)来设置套接字的类型和其对已ing的结构。 bind()函数的返回值为0时表示绑定成功,-1表示绑定失败,errno的错误值如表1所示。
表1 bind的errno值及含义
值 | 含义 | 备注 |
---|
EADDRINUSE | 给定地址已经使用 | | EBADF | sockfd不合法 | | EINVAL | sockfd已经绑定到其他地址 | | ENOTSOCK | sockfd是一个文件描述符,不是socket描述符 | | EACCES | 地址被保护,用户的权限不足 | | EADDRNOTAVAIL | 接口不存在或者绑定地址不是本地 | UNIX协议族,AF_UNIX | EFAULT | my_addr指针超出用户空间 | UNIX协议族,AF_UNIX | EINVAL | 地址长度错误,或者socket不是AF_UNIX族 | UNIX协议族,AF_UNIX | ELOOP | 解析my_addr时符号链接过多 | UNIX协议族,AF_UNIX | ENAMETOOLONG | my_addr过长 | UNIX协议族,AF_UNIX | ENOENT | 文件不存在 | UNIX协议族,AF_UNIX | ENOMEN | 内存内核不足 | UNIX协议族,AF_UNIX | ENOTDIR | 不是目录 | UNIX协议族,AF_UNIX | EROFS | socket节点应该在制度文件系统上 | UNIX协议族,AF_UNIX |
封装 socket 初始化函数
int socketInit(struct inputCommand *socketMes)
{
int s_fd;
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
//1.socket
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(socketMes->port));
inet_aton(socketMes->ipAdress,&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd,10);
printf("socket Server listening ...\n");
socketMes->fd=s_fd;
return s_fd;
}
?定义函数:int inet_aton(const char * cp, struct in_addr *inp);
? ? ? ? 函数说明:inet_aton()用来将参数cp 所指的网络地址字符串转换成网络使用的二进制的数字, 然后存于参数inp 所指的in_addr 结构中.
??htons的功能:uint16_t htons(uint16_t hostshort);
将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian) 参数u_short hostshort: 16位无符号整数 返回值:TCP / IP网络字节顺序. ? ? int atoi(const char *str)
把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。 ?
|