【整理】Socket编程之非阻塞connect(二)

简介:


      socket api 存在一批核心接口,而这一批核心接口就是几个看似简单的函数,尽管实际上这些函数没有一个是简单。connect 函数就是这些核心接口中的一个函数,它完成主动连接的过程。 

connect 函数的功能对于 TCP 来说就是完成面向连接的协议的连接过程,它的函数原型: 

linux下

?
1
2
3
#include<sys/socket.h>
#include<sys/types.h>
int connect( int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)
windows下 
?
1
2
3
4
5
int connect(
     SOCKET s,     // 没绑定套接口描述字
     const struct sockaddr FAR *name,   // 目标地址指针,目标地址中必须包含IP和端口信息。
     int namelen   // name的长度
     );

       面向连接的协议,在建立连接的时候总会有一方先发送数据(SYN),那么谁调用了 connect 谁就是先发送数据的一方。如此理解 connect 三个参数就容易了。我必需指定数据发送的目的地址,同时也必需指定数据从哪里发送,这正好是 connect 的前两个参数,而第三个参数是为第二个参数服务的。 

参数  sockfd   
      指定数据发送的套接字,解决从哪里发送的问题。内核需要维护大量 I/O 通道,所以用户必需通过这个参数告诉内核从哪个 I/O 通道(此处就是从哪个 socket 接口)中发送数据。 

参数  server_addr   
      指定数据发送的目的地,也就是服务器端的地址。这里服务器是针对 connect 说的,因为 connect 是主动连接的一方调用的,所以相应的要存在一个被连接的一方,被动连接的一方需要调用 listen 以接受 connect 的连接请求,如此被动连接的一方就是服务器了。  

参数  addrlen     
      指定 server_addr 结构体的长度。我们知道系统中存在大量的地址结构,但 socket 接口只是通过一个统一的结构来指定参数类型,所以需要指定一个长度,以使内核在进行参数复制的时候有个界限。  

返回值:没有错误发生,返回0;否则返回 SOCKET_ERROR(-1) 。

====================

      与所有的 socket 网络接口一样,connect 总会在某个时候可能失败,此时它会返回 -1 ,相应的 errno 会被设置,用户可能通过这个值确定是哪个错误。常见的错误有对方主机不可达或者超时错误,也可以是对方主机没有相应的进程在对应端口等待

connect 函数可用于  面向连接套接字   也可用于  无连接套接字   。 

无连接套接字   :对于无连接的套接字 (SOCK_DGRAM) ,该套接字与目标地址之间建立默认的对应关系,且在本地保存了对端的地址,这样后续的读写操作可以默认以连接的对端为操作对象,网络数据交互发生时可以直接使用 send ,而不是用 sendto 来向该地址发送数据;内核会丢弃所有发送给该套接字的源地址不是 connect 地址的报文。再次调用 connect 函数,若此时 name 和 namelen 两个参数均为空指针,就会将该套接字恢复为未连接状态,再调用 send 函数,系统会提示 WSAENOTCONN 错误码。 

面向连接套接字   :面向连接的套接字 (SOCK_STREAM) ,函数 connect 会引起调用端主动进行 TCP 的三次握手过程。结果通常是成功连接WSAETIMEDOUT (多次发送SYN报文,始终未收到回复)、WSAECONNREFUSED (目标主机返回 RST) 等。 

  当对端机器 crash 或者网络连接被断开(比如路由器不工作,网线断开等),此时发送数据给对端然后,读取本端 socket 会返回 ETIMEDOUT 或者EHOSTUNREACH 或者 ENETUNREACH (后两个是中间路由器判断服务器主机不可达的情况)。 

  当对端机器 crash 之后又重新启动,然后客户端再向原来的连接发送数据,因为服务器端已经没有原来的连接信息,此时服务器端回送 RST 给客户端,此时客户端读本地端口返回 ECONNRESET 错误。 

  当服务器所在的进程正常或者异常关闭时,会对所有打开的文件描述符进行 close ,因此对于连接的 socket 描述符则会向对端发送 FIN 分节进行正常关闭流程。对端在收到 FIN 之后端口变得可读,此时读取端口会返回 0 表示到了文件结尾(对端不会再发送数据)。  

  当一端收到 RST 导致读取 socket 返回 ECONNRESET ,此时如果再次调用 write 发送数据给对端则触发 SIGPIPE 信号,信号默认终止进程,如果忽略此信号或者从 SIGPIPE 的信号处理程序返回则 write 出错返回 EPIPE 。 

=================================  =====  
1) Broken PIPE 的字面意思是“管道破裂”。Broken PIPE 产生的原因是该管道的读端被关闭。 
2) Broken PIPE 经常发生在 Client 端通过 Socket 发送信息到 Server 端后,就关闭当前 Socket , 之后 Server 端回复信息给 Client 端时。 
3) 发生 Broken PIPE 错误时,调用写的进程会收到 SIGPIPE 信号,默认动作是导致当前进程终止。 
4) Broken PIPE 最直接的意思是:写入端出现的时候,PIPE 的另一端却休息或退出了,因此造成没有及时取走管道中的数据,从而系统异常退出。 

Client 端通过 PIPE 发送信息到 Server 端后,就关闭 Client 端 Socket , 这时 Server 端返回信息给 Client 端时就会产生 Broken PIPE 信号。  

======================================

  可以看出,只有当本地端口主动发送消息给对端时,才能检测出连接异常中断的情况,搭配 select 进行多路分离的时候,socket 收到 RST 或者 FIN 时候,select 返回可读(心跳消息就是用于检测连接的状态)。也可以使用 socket 的 KEEPLIVE 选项,依赖 socket 本身侦测 socket 连接异常中断的情况。


错误信息:  

EACCES, EPERM:用户试图在套接字广播标志没有设置的情况下连接广播地址或由于防火墙策略导致连接失败。 
EADDRINUSE:本地地址处于使用状态。 
EAFNOSUPPORT:参数 serv_add 中的地址非法。 
EAGAIN:没有足够空闲的本地端口。 
EALREADY:套接字为非阻塞套接字,并且原来的连接请求还未完成。 
EBADF:非法的文件描述符。 
ECONNREFUSED:远程地址并没有处于监听状态。 
EFAULT:指向套接字结构体的地址非法。 
EINPROGRESS:套接字为非阻塞套接字,且连接请求没有立即完成。 
EINTR:系统调用的执行由于捕获中断而中止。 
EISCONN:已经连接到该套接字。 
ENETUNREACH:网络不可到达。 
ENOTSOCK:文件描述符不与套接字相关。 

ETIMEDOUT:连接超时。


目录
相关文章
|
1天前
|
消息中间件 网络协议 网络安全
Python Socket编程:打造你的专属网络通道,基础篇与进阶篇一网打尽!
【7月更文挑战第26天】在网络编程领域,Python以简洁语法和强大库支持成为构建应用的首选。Socket编程为核心,实现计算机间的数据交换。
7 1
|
1天前
|
网络协议 Python
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
【7月更文挑战第26天】在网络的数字宇宙中,Python Socket编程是开启网络世界大门的钥匙。本指南将引领你从基础到实战,成为网络世界的建筑师。
6 2
|
2天前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
11 4
|
2天前
|
开发者 Python
Python Socket编程:不只是基础,更有进阶秘籍,让你的网络应用飞起来!
【7月更文挑战第25天】在网络应用蓬勃发展的数字时代,Python凭借其简洁的语法和强大的库支持成为开发高效应用的首选。本文通过实时聊天室案例,介绍了Python Socket编程的基础与进阶技巧,包括服务器与客户端的建立、数据交换等基础篇内容,以及使用多线程和异步IO提升性能的进阶篇。基础示例展示了服务器端监听连接请求、接收转发消息,客户端连接服务器并收发消息的过程。进阶部分讨论了如何利用Python的`threading`模块和`asyncio`库来处理多客户端连接,提高应用的并发处理能力和响应速度。掌握这些技能,能使开发者在网络编程领域更加游刃有余,构建出高性能的应用程序。
9 3
|
2天前
|
网络协议 开发者 Python
颠覆传统!Python Socket编程新思维,基础与进阶并重,打造卓越网络能力!
【7月更文挑战第25天】在数字时代,网络通信至关重要,Python的Socket编程简化了这一复杂领域,使初学者也能轻松上手。通过Python的`socket`模块,我们能快速搭建服务器与客户端,实现数据交换。示例代码展示了如何创建、绑定及监听Socket,以及收发消息。掌握基础后,可利用asyncio库探索异步编程,提升通信效率,处理多连接。Python的Socket编程,结合传统与现代技术,助力开发者在网络通信领域取得非凡成就。
|
16天前
|
Java 数据格式
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
18 0
|
18天前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解
|
22天前
|
Java API 开发者
Java中的Socket编程与应用
Java中的Socket编程与应用
|
23天前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解