1. socket函数
#include <sys/socket.h> //成功返回非负,失败返回-1 int socket(int family, int type, int protocol);
参数说明:
family指明协议族取值如下图
type指明套接字类型
protocol指明协议
当Protocol值为0时系统根据family和type的组合指定默认值
关于AF_XXX和PF_XXX
AF_前缀表示地址族,PF_前缀表示协议族。历史想法:单个协议族可以支持多个地址族,PF_值用于创建套接字,AF_值用于套接字地址结构。实际上支持多个地址族的协议族从来没实现过,现<sys/socket.h>中给出的PF_值大多和AF_值相等。
2. connect函数
#include <sys/socket.h> int connect(int sockfd, const struct sockaddr *servaddr, socklet_t addrlen);
如果是TCP套接字,此函数触发TCP三次握手连接,在连接成功或出差时才返回,错误可能有以下情况:
1)TCP客户没有收到SYN分节响应;
2)SYN的响应是RST,这是一种硬错误,会马上返回ECONNREFUSED错误;
3)发出的SYN在中间某个路由引发"destination unreachable"。
说明:connect函数导致当前套接字从COLSED状态转移到SYN_SEND状态,若成功则转移到ESTABLISHED状态,若失败则该套接字不再可用,必须关闭。所以每次connect失败后都必须close当前套接字,并重新调用socket创建。
3. bind函数
#include <sys/socket.h> int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
参数说明:对于TCP调用bind函数可以指定一个端口或指定一个IP地址,也可以两者都不指定或两者都指定。
1)服务器一般都会指定端口,例外是远程过程调用(RCP);
2)进程可以把一个特定的IP捆绑到它的套接字,但是次IP必须是其所在主机的网络接口之一。
指定IP或端口预期值如下图:
对于IPv4通配地址通常由INADDR_ANY指定。
bind常返回的一个错误是EADDRINUSE(Address already in use)
4. listen函数
#include <sys/socket.h> int listen(int sockfd, int backlog);
listen由服务器调用,做以下两件事:
1)socket函数创建套接字时,它被认为是主动套接字,listen把一个未连接的主动套接字转换成一个被动套接字。listen导致套接字从CLOSE状态转换到LISTEN状态;
2)为内核规定相应套接字排队的最大连接数(可以看成包含已经连接完成连接ESTABLISHED状态的和未完成连接的)。
backlog参数值的解析:
1)不要把backlog参数指定为0,因为不同的实现处理方式不同;
2)backlog并不是未完成连接队列+已完成连接队列的和。
3)backlog值与排队连接的最大数目不同系统不同。这个值最好设置成可配置的。
6. accept函数
#include <sys/socket.h> int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
说明:
- cliaddr与addrlen返回已连接的客户进程的协议地址,addrlen是值-结构参数
- 对客户的身份不感兴趣可以把chiaddr与addrlen都设置成NULL
- 区分监听套接字和已连接套接字。监听套接字由socket创建在服务器的生命周期内一直存在,已连接套接字是连接成功时accept返回的值,当客户端断开连接时已连接套接字也被关闭。
7. fork和exec函数
8. 并发服务器:父子进程共享套接字描述符。每个套接字都有一个引用计数。
9.close函数
#include <unistd.h> int close(int sockfd);
10. getsockname和getpeername
#include <sys/socket.h> int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
说明:
- getsockname:在一个没有调用bind的TCP客户上,connect成功返回后,其返回由内核赋予该连接的本地IP和端口号;以端口号0调用bind后,getsockname用于返回由内核赋予的本地端口号;getsockname可获得某个套接字的地址族;以通配IP调用bind的服务器上,和客户端连上后getsockname可获得由内核赋予的本地ip地址
- 服务器是由调用过accept某个进程通过调用exec执行程序时,它能获取客户身份的唯一途径是经过getpeername。(fock->exec)
注:两个函数最后一个参数都是值-结果参数。
返回套接字地址族例子:
int sockfd_tofamily(int sockfd) { struct sockaddr_storage ss; socklen_t len; len = sizeof(ss); if(getsockname(sockfd, (SA*) &ss, &len) < 0) { return -1; } return ss.ss_family; }