《unix网络编程》(8)基本TCP套接字

套接字函数


socket函数

创建一个套接字用于通信:

#include <sys/socket.h>
int socket(int family, int type, int protocol);  //成功返回非负的描述符,出错返回-1
/*
参数:
   family:指定通信协议族(protocol family),常用取值AF_INET(IPv4)
   type:指定socket类型, 流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW
   protocol:协议类型,常用取值0, 使用默认协议
*/

bind函数

把一个本地协议地址赋予一个套接字,对网际协议,协议地址是32位IPv4地址或128位IPv6地址与16位TCP或UDP端口的组合。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
        bind第二个参数是 const的,所以无法返回所选的值。因此,如果内核分配临时端口(指定端口为0则内核在bind调用时选择一个临时端口),那么 为了获取临时端口的值只能使用getsockname来返回协议地址。如果指定通配IP,那么内核将在 套接字已连接(TCP)或 已在套接字上发出数据报时(UDP)才选择一个本地IP。

bind可以指定一个端口号或一个IP也可以两个都不指定

      (1)TCP客户或服务器未曾绑定一个端口,当调用connect或listen时,内核为响应的套接字选择临时端口。这对于TCP客户是正常的,但对于TCP服务器却很罕见,因为TCP服务器是通过众所周知的端口来连接的

       (2)当绑定IP:对客户端来说就指定了源IP地址;对服务器来说就它就只接收从这个IP地址发起的连接。所以通常服务器不绑定IP。当客户连接套接字时,内核根据所用外出网络接口选择源IP。服务器没绑定IP的话,内核会把客户发来的SYN的目的地址作为服务器的源IP


connect函数

TCP客户与TCP服务器建立连接。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*
参数:
   sockfd:未连接套接字
   addr:要连接的套接字地址
   addrlen:第二个参数addr长度
*/
         客户调用connect前不必非要调用bind,因为如果需要,内核会确定源IP并选择临时端口。

 如果是TCP套接字,调用connect会激发三次握手,而且仅连接建立成功或出错才返回,其中错误有以下几种:

        (1)客户没收到SYN分节的响应,返回ETIMEDOUT错误。会发几次SYN,仍未收到响应会返回该错误。

         (2)若对客户SYN响应是RST(复位),表明在我们连接的端口上没有进程在等待连接(例如服务器没运行)。这是错误,客户收到RST立即返回ECONNREFUSED错误。

        (3)若客户发出的SYN在中间某路由上引发“destination unreachable”(目的地不可达)ICMP错误,这是软错误。客户内核保存该信息,继续隔一段时间就发SYN,若仍没响应,则保存ICMP错误作为EHOSTUNREACH或ENETUNREACH错误返回给进程。


        按照TCP状态转换图(参考《unix网络编程》(3)TCP连接的建立和终止),connect导致当前套接字由CLOSED状态转移到SYN_SENT状态,若成功则转移到ESTABLISHED状态

        若connect失败则该套接字不可用,必须关闭,不能对它再次调用connect,必须close描述符然后重新调用socket。


listen函数

该函数仅由TCP服务器调用,完成两件事:

       (1)listen函数应该用在调用socket和bind函数之后, 并且用在调用accept之前。用于将一个套接字从一个主动套接字(socket建立的是主动套接字)转变成为被动套接字,指示内核应该接受指向该套接字的连接请求。

       (2)第二个参数指定内核应该为相应套接字排队的最大连接个数

int listen(int sockfd, int backlog);
/*
backlog说明:对于给定的监听套接口,内核要维护两个队列: 1、已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程(SYN_RCVD状态)
 2、已完成连接的队列(ESTABLISHED状态)但是两个队列长度之和不能超过backlog
*/

         按照TCP状态转换图(参考 
《unix网络编程》(3)TCP连接的建立和终止 
),调用listen导致套接字从CLOSED转换到LISTEN。 

accept函数

该函数由TCP服务器调用。用于从已经完成连接队列对头返回下一个已完成连接;若已完成队列空,则进程睡眠(如果套接字为默认的阻塞方式)。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/*
参数:
   sockfd:服务器套接字
   addr:将返回对等方的套接字地址, 不关心客户身份的话, 可以设置为NULL
   addrlen:返回对等方的套接字地址长度, 不关心的话可以设置成为NULL, 否则一定要初始化
*/
注意:accept函数称其第一个参数为 监听套接字描述符(由socket创建,用于bind和listen);称其返回值为 已连接套接字描述符

区分两个套接字:

         服务器通常只有一个监听套接字,在该服务器生命周期内一直存在。内核为每个服务器接受的客户连接创建一个已连接套接字(三次握手完成);当服务器完成对客户的服务时,相应的已连接套接字被关闭

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值