网络编程Socket之TCP之connect具体解释
对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错误作为EHOSTUNREACH或ENETUNREACH错误返回给进程。
若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具体解释的更多相关文章
- java网络编程socket\server\TCP笔记(转)
java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04| 分类: Socket | 标签:java |举报|字号 订阅 1 TCP的开销 a ...
- 网络编程Socket之TCP之close/shutdown具体解释(续)
接着上一篇网络编程Socket之TCP之close/shutdown具体解释 如今我们看看对于不同情况的close的返回情况和可能遇到的一些问题: 1.默认操作的close 说明:我们已经知道writ ...
- python网络编程(Socket、TCP、UDP)
Socket 是网络编程的一个抽象概念,通常我们用一个Socket表示 "打开了一个网络链接",而打开一个Socket 需要知道目标计算机的IP 地址和端口号,再指定协议类型即可. ...
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
一.TCP socket ipv6与ipv4的区别 服务器端源代码如下: #include <stdio.h> #include <stdlib.h> #include < ...
- 网络编程Socket之TCP
服务端: 1. 创建 ServerSocket 对象并监听一个端口 2. 调用accept()方法等待客户端的连接(阻塞式) 3. 输入流(记取客户端发送过来的数据) 4. 输出流(响 ...
- 网络编程Socket它TCP它TIME_WAIT国家具体解释
下面我们用最简单的一对一的客户server编程模型重现遇到的一些问题: 初学者socket当写作socket名其妙的问题.比方说bind函数返回的常见错误是EADDRINUSE 使用以下的程序重现这个 ...
- 二、网络编程-socket之TCP协议开发客户端和服务端通信
知识点:之前讲的udp协议传输数据是不安全的,不可靠不稳定的,tcp协议传输数据安全可靠,因为它们的通讯机制是不一样的.udp是用户数据报传输,也就是直接丢一个数据包给另外一个程序,就好比寄信给别人, ...
- python_网络编程socket(TCP)
服务端: import socket sk = socket.socket() #创建对象 sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
随机推荐
- hdu 5078 Osu!(鞍山现场赛)
Osu! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Sub ...
- [WASM] Call a JavaScript Function from WebAssembly
Using WASM Fiddle, we show how to write a simple number logger function that calls a consoleLog func ...
- spark原理介绍 分类: B8_SPARK 2015-04-28 12:33 1039人阅读 评论(0) 收藏
1.spark是一个基于内存计算的开源的集群计算系统,目的是让数据分析更加快速.因此运行spark的机器应该尽量的大内存,如96G以上. 2.spark所有操作均基于RDD,操作主要分成2大类:tra ...
- php 面试题一(看视频的学习量比网上瞎转悠要清晰和明了很多)(看视频做好笔记)(注重复习)
php 面试题一(看视频的学习量比网上瞎转悠要清晰和明了很多)(看视频做好笔记)(注重复习) 一.总结 1.无线分类的本质是树(数据结构)(数的话有多种储存结构可以实现,所以对应的算法也有很多),想到 ...
- js自动记忆用户名(可以设置cookie多存几天)
js自动记忆用户名(可以设置cookie多存几天) 一.总结 1.记住密码:因为cookie是存在本地的,也可以多存几天,所以记住密码的操作只需要读取cookie,将其中的账号密码直接显示在输入框就好 ...
- 数值优化(Numerical Optimization)学习系列-文件夹
概述 数值优化对于最优化问题提供了一种迭代算法思路,通过迭代逐渐接近最优解,分别对无约束最优化问题和带约束最优化问题进行求解. 该系列教程能够參考的资料有 1. <Numerical Optim ...
- Linux基本命令(二)
1. 输出重定向命令:> Linux允许将命令执行结果重定向到一个文件,本应显示在终端上的内容保存到指定文件中. 如:ls > test.txt ( test.txt 如果不存在,则创建, ...
- Mybatis中sql语句中的in查询,一定要判断null的情况
不严谨的写法,可能会报错:in (),这种情况不符合mysql的语法. select from loanwhere LOAN_ID in <foreach item="item&quo ...
- Linux下iptables屏蔽IP和端口号
http://blog.csdn.net/kobejayandy/article/details/24332597 iptables 屏蔽端口
- 入坑cordova
原文:入坑cordova 因项目需要入坑cordova,奔跑吧骚年,目前只是要求安卓平台,下面都是以安卓为例 最好的学习资料还是官网. https://cordova.apache.org/ http ...