第四章 基本TCP套接字编程

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;
}
原文地址:https://www.cnblogs.com/4tian/p/2622826.html