socket编程之connect()

本文详细介绍了connect()系统调用在套接字编程中的作用,用于将文件描述符引用的套接字连接到指定地址。连接过程包括三次握手,涉及EACCES、EADDRINUSE等错误类型。服务端通过socket()—bind()—listen()—accept()建立连接,客户端则通过socket()—connect()。同时,文章提到了不同类型的套接字在连接过程中的差异,并给出了简单的实战项目链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5 connect()

connect() 系统调用将文件描述符 sockfd 引用的套接字连接到 addr 指定的地址。

2.1 包含头文件
#include <sys/types.h>        
#include <sys/socket.h>
2.2 函数主体
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数解释:

  • int sockfd

​ socket()函数返回的未被使用的文件描述符

  • const struct sockaddr *addr

​ 该地址为所要连接的socket的地址,connect() 系统调用将文件描述符 sockfd 引用的套接字连接到 addr 指定的地址。

​ 如果套接字 sockfd 的类型为 SOCK_DGRAM,则 addr 是默认情况下数据报发送到的地址,也是接收数据报的唯一地址。如果套接字的类型为 SOCK_STREAM 或 SOCK_SEQPACKET,则此调用将尝试与绑定到 addr 指定的地址的套接字建立连接。通常,基于连接的协议套接字可能只成功连接()一次;无连接协议(例如UDP数据报)套接字可以多次使用 connect() 来更改其关联。

  • socklen_t addrlen

​ addrlen 参数指定 addr 的大小。

2.3 返回值

如果连接成功,则返回0;出错时,返回-1,错误类型如下:

错误类型解释
EACCES, EPERM用户尝试连接到广播地址,但未启用套接字广播标志,或者由于本地防火墙规则,连接请求失败。
EACCES(本地套接字)对套接字文件的写入权限被拒绝,或者对路径前缀中的某个目录的搜索权限被拒绝。
EADDRINUSE本地地址已在使用中。
EAFNOSUPPORT传递的地址其sa_family字段中不正确。
EAGAIN路由缓存中的条目不足。
EALREADY套接字为非阻塞套接字,且上一次尝试连接还未完成。
EBADFsockfd不是有效的文件描述符。
ECONNREFUSED流套接字上的 connect() 发现没有在监听的远程地址。
EFAULT套接字结构地址位于用户的地址空间之外。
EINTR本次系统调用被捕获的信号中断。
EISCONN套接字已连接。
ENETUNREACH网络无法访问。
EPROTOTYPE套接字类型不支持请求的通信协议。例如,尝试将 UNIX 域数据报套接字连接到流套接字时,可能会发生此错误。
ETIMEDOUT尝试连接时超时。 服务器可能太忙,无法接受新连接。 对于 IP 套接字,在服务器上启用 syncookie 时,超时可能很长。
2.4 小结

介绍完connect()函数之后,socket编程的五个基本函数便已经全部介绍完毕,基于这五个函数的两个或多个套接字便可以正常建立连接,进行读写操作,读写操作用到的函数将在后面的小节中继续总结更新。此处,先对服务端和客户端建立连接的过程进行总结。

我们创建的socket的数据结构如下图,每个进程都会维护一个这样的文件描述符表。

在这里插入图片描述

服务端与客户端建立连接的流程如下:

  • 服务端:socket()—bind()—listen()—accept()(阻塞…)
  • 客户端:socket()—connect()(阻塞…)

在客户端调用connect()尝试连接服务端时,双方三次握手建立连接的流程如下:

在这里插入图片描述

对上图进一步补充说明:

  • 客户端调用connect()时,双方开始三次握手建立连接,建立连接流程如下:

    • 客户端调用connect()后阻塞,向服务端发送SYN J包,此时客户端进入SYN_SENT状态,等待服务端发送ACK+SYN
    • 服务端收到SYN报文后,进入SYN_RCVD状态,发送ACK J+1,SYN K给客户端,发送成功后进入ESTABLISTED状态。
    • 客户端收到ACK+SYN后,connect()返回,进入ESTABLISTED状态,向服务端发送ACK K+1。
    • 服务端收到ACK包后,accept()函数返回,返回值为监听socket维护的第一个队列中的第一个socket。
  • 监听套接字会维护两个连接队列,第一个为进入ESTABLISTED状态的套接字队列,第二个为ESTABLISTED状态之前的套接字队列。可以通过“netstat -an”命令查看主机目前所维护的来连接。

在这里插入图片描述

  • 服务端和客户端socket初始化步骤为何有区别:

    • 服务端,顾名思义用来提供服务,不同的端口提供不同的服务,因此需要绑定唯一的端口来表明该服务的地址,这样客户端才可以找到该服务的位置。
    • 客户端,建立连接也需要一个端口,但是并不需要固定一个端口,因此默认有系统随机分配。同时面向连接的TCP数据报中会包含主机与目的主机的IP和端口,因此,不需要再应用层使用bind()进行绑定。

函数的简单实战可以通过这个项目:代码传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值