socket编程之connect()

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()进行绑定。

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

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
connect函数是在socket编程中用于建立与远程主机的连接的函数。它的原型为: ```C int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); ``` 参数解释: - `sockfd`:需要连接的套接字描述符。 - `addr`:指向存放目标主机地址信息的结构体 sockaddr 的指针。 - `addrlen`:存放目标主机地址信息结构体的长度。 connect函数的工作流程如下: 1. 创建一个套接字。 2. 使用connect函数,向指定的远程主机发起连接请求。 3. 阻塞等待服务器处理连接请求。 4. 如果连接成功,则返回0;如果连接失败,则返回-1,错误号存储在errno中。 注意事项: - 在使用connect函数时,需要确保套接字已经创建并且正确初始化。 - connect函数通常是阻塞的,即在连接建立之前会一直等待。 - 连接成功后,可以使用该套接字进行数据的收发操作。 示例代码如下所示: ```C #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int sockfd; struct sockaddr_in serv_addr; // 创建套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); exit(1); } // 设置远程主机地址信息 serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(8080); serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 发起连接请求 if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { perror("connect"); exit(1); } printf("连接成功!\n"); // 关闭套接字 close(sockfd); return 0; } ``` 以上示例代码展示了如何使用connect函数建立与远程主机的连接。注意需要将目标主机的IP地址和端口号正确设置。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值