对TCP套接字调用connect会激发三次握手,例如以下:

client是主动打开连接的一端,会发送第一个SYN分节,然后等待确认,此时连接状态为SYN_SENT,当收到服务端的确认后连接建立,状态变为ESTABLISHED

server是被动打开连接的一端,调用listen导致套接字从CLOSED状态变为LISTEN状态,当收到来自client的SYN分节以后状态变为SYN_RCVD,然后发送第二个SYN分节,等待client的确认,收到client的确认以后连接建立,状态变为ESTABLISHED

三次握手中的两个SYN分节都会告诉对端本端在同一连接中发送数据的初始序列号,ACK的确认号是本端所期待的下一个序列号,SYN和FIN都占领一个字节的序列号空间;

SYN中携带的TCP选项:

MSS:告知对端本端在本连接中得每一个TCP分节中愿意接受的最大数据量,发送端TCP使用接收端的MSS作为所发送分节的最大大小,我们能够通过TCP_MAXSEG套接字选项提取和设置这个TCP选项,TCP_MAXSEG选项原本是仅仅读选项,4.4BSD限制应用进程仅仅能降低其值,不能添加其值。

窗体规模选项:TCP连接不论什么一端可以通告对端的最大窗体大小是65535,由于在TCP首部中,对应地字段占16位;SO_RCVBUF套接字选项影响这个TCP选项,套接字接收缓冲区中可用空间的大小限定了TCP通告对端的窗体大小;

时间戳选项:这个选项对于快速网络连接是必要的,它能够防止由失而复得的分组可能造成的数据损坏,这个失而复得是指由临时的路由原因造成的迷途,路由稳定后又正常到达目的地,快速网络中32位的序列号非常快就可能循环一轮又一次使用,假设不用时间戳选项,失而复得的分组所承载的分节可能与再次使用同样序列号的真正分节发生混淆;

connect(套接字默认堵塞)出错返回的情况:

1. 调用connect时内核发送一个SYN分节,若无响应则等待6s后再次发送一个,仍无响应则等待24s再发送一个,若总共等了75s后仍未收到响应则返回ETIMEDOUT错误;

2. 若对客户的SYN的响应是RST,则表示该server主机在我们指定的port上面没有进程在等待与之连接,比如server进程没执行,客户收到RST就立即返回ECONNREFUSED错误;

3. 若客户发出的SYN在中间的某个路由上引发了一个“destination unreachable”(目的不可达)ICMP错误,客户主机内核保存该消息,并按1中所述的时间间隔发送SYN,在某个规定的时间(4.4BSD规定75s)仍未收到响应,则把保存的ICMP错误作为EHOSTUNREACHENETUNREACH错误返回给进程。

若connect失败则该套接字不再可用,必须关闭,我们不能对这种套接字再次调用connect函数。

在每次connect失败后,都必须close当前套接字描写叙述符并又一次调用socket。

我们重现一下这些错误:

首先看下下面系统定义:

#define
ENETUNREACH 51
/* Network is unreachable */

#define
ETIMEDOUT 60
/* Operation timed out */

#define
ECONNREFUSED 61
/* Connection refused */

client:

<span style="font-size:12px;">int main(int argc, const char * argv[])
{ struct sockaddr_in serverAdd; bzero(&serverAdd, sizeof(serverAdd));
serverAdd.sin_family = AF_INET;
serverAdd.sin_addr.s_addr = inet_addr(SERV_ADDR);
serverAdd.sin_port = htons(SERV_PORT); int connfd = socket(AF_INET, SOCK_STREAM, 0); int connResult = connect(connfd, (struct sockaddr *)&serverAdd, sizeof(serverAdd));
if (connResult < 0) {
printf("连接失败,errno = %d\n",errno);
close(connfd);
return -1;
}
else
{
printf("连接成功\n");
}
close(connfd);
return 0;
}
</span>

服务端:

<span style="font-size:12px;">int main(int argc, const char * argv[])
{ struct sockaddr_in serverAdd;
struct sockaddr_in clientAdd; bzero(&serverAdd, sizeof(serverAdd));
serverAdd.sin_family = AF_INET;
serverAdd.sin_addr.s_addr = htonl(INADDR_ANY);
serverAdd.sin_port = htons(SERV_PORT); socklen_t clientAddrLen; int listenfd = socket(AF_INET, SOCK_STREAM, 0);
int yes = 1;
setsockopt(listenfd,
SOL_SOCKET, SO_REUSEADDR,
(void *)&yes, sizeof(yes)); if (listenfd < 0) {
printf("创建socket失败\n");
close(listenfd);
return -1;
} int bindResult = bind(listenfd, (struct sockaddr *)&serverAdd, sizeof(serverAdd));
if (bindResult < 0) {
close(listenfd);
printf("绑定port失败,errno = %d\n",errno);
return -1;
}
else
{
printf("绑定port成功\n");
} // listen(listenfd, 20);
sleep(60*5); return 0;
}
</span>

先执行服务端,再执行client,client在休眠一段时间以后会复现第一个错误,client打印例如以下信息:

连接失败,errno
60

不执行服务端,直接执行client会复现另外一种情况,直接打印例如以下信息:

连接失败,errno
61

关掉wifi,直接执行会复现第三种情况,直接打印例如以下信息:

连接失败,errno
 51

这里有个疑问,要是服务端打开屏蔽listen的那行代码会怎么样,再执行,client打印:

连接成功

我们服务端没有调用accept代码呀,这是由于调用listen方法后,内核为不论什么一个给定的监听套接字维护两个队列:未完毕连接队列和已完毕连接队列例如以下图所看到的;当客户SYN到达时,假设队列是满的,TCP就忽略该分节,但不会发送RST;当进程调用accept时,已完毕队列的对头项将返回给进程,假设队列是空,则堵塞(套接字默认堵塞);

也就是说仅仅要我调用了listen方法后,服务端就打开了三次握手的开关,可以处理来自client的SYN分节了,仅仅要三次握手完毕,client就会connect成功,而跟服务端调用accept没不论什么关系,accept仅仅是去取已完毕连接队列的对头项。

如图为TCP监听套接字的两个队列:

參考:

《UNIX Network ProgrammingVolume 1, Third Edition: TheSockets Networking API》

网络编程Socket之TCP之connect具体解释的更多相关文章

  1. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

  2. 网络编程Socket之TCP之close/shutdown具体解释(续)

    接着上一篇网络编程Socket之TCP之close/shutdown具体解释 如今我们看看对于不同情况的close的返回情况和可能遇到的一些问题: 1.默认操作的close 说明:我们已经知道writ ...

  3. python网络编程(Socket、TCP、UDP)

    Socket 是网络编程的一个抽象概念,通常我们用一个Socket表示 "打开了一个网络链接",而打开一个Socket 需要知道目标计算机的IP 地址和端口号,再指定协议类型即可. ...

  4. IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类

    一.TCP socket ipv6与ipv4的区别 服务器端源代码如下: #include <stdio.h> #include <stdlib.h> #include < ...

  5. 网络编程Socket之TCP

            服务端: 1. 创建 ServerSocket 对象并监听一个端口 2. 调用accept()方法等待客户端的连接(阻塞式) 3. 输入流(记取客户端发送过来的数据) 4. 输出流(响 ...

  6. 网络编程Socket它TCP它TIME_WAIT国家具体解释

    下面我们用最简单的一对一的客户server编程模型重现遇到的一些问题: 初学者socket当写作socket名其妙的问题.比方说bind函数返回的常见错误是EADDRINUSE 使用以下的程序重现这个 ...

  7. 二、网络编程-socket之TCP协议开发客户端和服务端通信

    知识点:之前讲的udp协议传输数据是不安全的,不可靠不稳定的,tcp协议传输数据安全可靠,因为它们的通讯机制是不一样的.udp是用户数据报传输,也就是直接丢一个数据包给另外一个程序,就好比寄信给别人, ...

  8. python_网络编程socket(TCP)

    服务端: import socket sk = socket.socket() #创建对象 sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) ...

  9. Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型

    Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...

随机推荐

  1. proxool数据库连接池用法

    今天给大家介绍一种新的数据连接池实现方式--proxool数据库连接池,这是一个健壮.易用的连接池.以下通过一个Demo说明一下怎样使用: 项目结构例如以下: DBLink.java文件里的代码: p ...

  2. 黑马day18 jquery高级特性&amp;Ajax的load方法

    介绍jquery中的load方法: (1).前面没有jquery.修饰,能够判断出他是一个普通的非全局函数(也就是说是一个局部函数):$.,$().,jquery.等修饰的就是全局函数.没有这些修饰的 ...

  3. php二维数组中的查找(善于利用基础函数)

    php二维数组中的查找(善于利用基础函数) 一.总结 真没必要完整的写函数,善于借用 1.array_search()是在以为数组中来找,现在我们要在二维数组数组中来,肯定要借用这个 2.!==fal ...

  4. EntityFrameworkCore 中的 Attach 方法

    Attach 的坑 Model Filed Database Value Console Value User Phone +123000000000 +12333333333 User Email ...

  5. jquery中ajax中post方法(多学习:洞悉原理,触类旁通)(函数封装思想)

    jquery中ajax中post方法(多学习:洞悉原理,触类旁通)(函数封装思想) 一.总结 1.多看学习视频:洞悉原理,触类旁通, 2.函数封装:$.post(URL,data,callback); ...

  6. CentOS7下安装Mysql失败经历--CentOS7使用yum安装和卸载Mysql过程

    起因 自己租用的BandwagonVPS上安装了个CentOS7,然后开始安装各种软件,结果yum安装MySQL发现MySQL在yum源中的Mysql不对劲,于是自己百度搜索安装方法. 终于我搜到了这 ...

  7. Surf算法特征点检测与匹配

    Speeded Up Robust Features(SURF,加速稳健特征),是一种稳健的局部特征点检测和描述算法.最初由Herbert Bay发表在2006年的欧洲计算机视觉国际会议(Europe ...

  8. 【poj2528】Mayor's posters

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 59254   Accepted: 17167 Description The ...

  9. 利用QPainter绘制各种图形(Shape, Pen 宽带,颜色,风格,Cap,Join,刷子)

    利用QPainter绘制各种图形 Qt的二维图形引擎是基于QPainter类的.QPainter既可以绘制几何形状(点.线.矩形.椭圆.弧形.弦形.饼状图.多边形和贝塞尔曲线),也可以绘制像素映射.图 ...

  10. git基本原理

    git基本原理 一.总结 一句话总结:把原理那张图图背下来 1.git中的四大区,除了远程仓库和本地仓库,剩下两个是什么? 解答:工作区和暂存区. 2.git中的四大区(例如远程仓库和本地仓库),他们 ...