TCP Socket

本文主讲tcp和tcp的抽象socket。
由于tcp过于复杂,你可以把本文当作专栏看。本文的问题和回答是本人那时的突发奇想和所思所想,不代表此时。可能那时会错误,此时也不对。问题会伴随着本人的需要而提出,回答会随着本人的认知而更新。

(暂定 重大问题待修改)

1.tcp连接是怎么发送

端:指端口				

------这个问题主要是因为已经习惯了A端和B端发送数据是在tcp连接之后,那在tcp建立连接之前,tcp连接又是谁发送。这个问题关键在于把tcp连接看成数据,则tcp连接是怎么发送的。已知 两端之间不论谁向谁建立连接必须要先发一个SYN包。如A端向B端建立连接则A端要先发送一个SYN包。则问题等价于第一个SYN包是怎么发送的。那么,这个问题成立的前提是A有A端,B有B端,也就是AB两端先安装TCP。接着A端向B端发送SYN包。问题好像一下字明了了。SYN包由IP发送。这应该是问题答案。展开下答案:AIP向B发送数据。BIP收到数据后再按TCP解析,此时数据成为SYN包。成功发送。但有个衍生问题,就是这个问题成立的前提是不是只要B有B端就可以。

衍生问题

------因为从答案的流程来看似乎不需要A支持TCP,A的IP只要能向BIP发送数据就行了。经过我的深思熟虑,觉得就是这样的,即便是以A有数据链路层,B有IP层为例也是如此。因为可以把A和B网线连接在一起就能发送了。此时B有IP,A无IP。我们假设人类有收发器可以收发数据。如图
在这里插入图片描述

那么,A是可以向B发送数据的,B再经大脑解析。B也可以向A发送数据,但A无法解析数据。

2.tcp连接缓冲区大小

每个tcp连接也就是每个socket都有两个缓冲区,分别为读写缓冲区。

查看缓冲区默认大小

------有两种方法
------第一种 查看文件 (此会在2.衍生问题补充)
cat /proc/sys/net/ipv4/tcp_rmem //接收缓冲区
4096 87380 6291456

cat /proc/sys/net/ipv4/tcp_wmem //发送缓冲区
4096 16384 4194304 //第一个最小值,第二个默认值,第三个最大值。
这个只有默认值有效,其他的没用。

------第二种 getsockopt

#include<sys/socket.h>
//服务器套接字
int sock_server = socket(AF_INET, SOCK_STREAM, 0);

//显示套接字缓冲区默认大小
int val;
socklen_t valLen = sizeof(int);

getsockopt(sock_server, SOL_SOCKET, SO_RCVBUF, &val, &valLen);
cout << "套接字接收默认大小 :" << val<< endl;
getsockopt(sock_server, SOL_SOCKET, SO_SNDBUF, &val, &valLen);
cout << "套接字发送默认大小 :" << val<< endl;

修改缓冲区大小

------第二种 setsockopt
修改规则:
1.当要修改的值val <= 1/2最小值,则设置成最小值
2.当1/2最小值 < val <= 1/2最大值,则设置2val
3.当val > 1/2最大值,则设置最大值。
直观总结:即不论val多小,也会返回最小;不论val多大,也不会超过最大。其余返回2
val。
读缓冲最小:2304 发送最小:4608。最大在下面。

//修改并显示
val = 1;
setsockopt(sock_server, SOL_SOCKET, SO_RCVBUF, &val, sizeof(int));
getsockopt(sock_server, SOL_SOCKET, SO_RCVBUF, &val, &valLen);
cout << "套接字接收大小 :" << val << endl;

val = 1;
setsockopt(sock_server, SOL_SOCKET, SO_SNDBUF, &val, sizeof(int));
getsockopt(sock_server, SOL_SOCKET, SO_SNDBUF, &val, &valLen);
cout << "套接字发送大小 :" << val << endl;

查看修改最大值

------查看最大值
cat /proc/sys/net/core/rmem_max //接收
212992
cat /proc/sys/net/core/wmem_max //发送
212992
此值仅是最大值的1/2,也就是最大值为425984。
1/2的意义在于应用程序中的val值不能超过212992,否则没有意义。

------修改最大值
sudo sysctl -w net.core.rmem_max=1048576(1M)
结合上面 也就是最大值为2M,而这个1M的意义在于程序中的变量不应该超过这个值。

衍生问题

------我们会发现
cat /proc/sys/net/ipv4/tcp_rmem 和 cat /proc/sys/net/core/rmem_max 显示的接收最大值相差甚远
4096 87380 6291456       212992
其实cat /proc/sys/net/ipv4/tcp_rmem是没一点用的。只有中间的默认值准确,其他两个都不准确。而创建套接字是根据它创建。所以它唯一的用处就是在没有程序时可以通过命令行来看或修改默认值

3.缓冲区读写

------我们应该增加一个意识,任何一个缓冲区读写之前都应该判断可读可写。
设缓冲区为buff。buff.read(),buff.write()对这个缓冲区进行读写。

if(可读)
	buff.read();
if(可写)
	buff.write();

缓冲区可读可写

------怎么判断可读可写
可读:缓冲区不空 (也就是 缓冲区有数据)
可写:缓冲区不满 (也就是 缓冲区有空地方)
设 buff.isEmpty(),buff.isFull()判断buff是否空/满

if(!buff.isEmpty())	|	if(可读)
	buff.read();	|		buff.read();
if(!buff.isFull())	|	if(可写)
	buff.write();	|		buff.write();


buff.dataLen:数据长度 (>=0)
buff.buffSize:缓冲区大小(一般用size表示长度固定,len表示长度可变)
buff.empLen:空地方长度= 缓冲区大小 - 数据长度 (>=0)

if(buff.dataLen)	|	if(!buff.isEmpty())		
	buff.read();	|		buff.read();			
if(buff.empLen)		|	if(!buff.isFull())		
	buff.write();	|		buff.write();			

而isEmpty(),isFull(),empLen完全可以由缓冲区大小,数据长度而来。
所以,对于缓冲区来说,最主要的概念只有两个缓冲区大小和数据长度

缓冲区水位

if(buff.dataLen)
	buff.read();
if(buff.empLen)
	buff.write();

------上段代码是根据缓冲区有数据,有空地方而写。
即dataLen和empLen=1就可读写。
此时他们的阙值为1。我们可以对这个阙值设置。
例如提高,将阙值设为10

if(buff.dataLen > 10)	|
	buff.read();		|
if(buff.empLen > 10)	|
	buff.write();		|

此时只有数据量和空地方大于10才进行读写。
缓冲区里这个值被称为 水位(water level)。
设 buff.waLevel:水位

buff.waLevel = 10/1;	//10或1
if(buff.dataLen > buff.waLevel)
	buff.read();
if(buff.empLen > buff.waLevel)
	buff.write();
//我们会发现这样写代码dataLen和empLen为1时不能读写 因此
if(buff.dataLen >= buff.waLevel)	
	buff.read();
if(buff.empLen >= buff.waLevel)
	buff.write();
//这其实仅仅是对if(buff.dataLen)理解不同罢了
//					buff.read();
//我们可以把他看做是大于0,也可以看作是等于1
//所以有两套代码格式,这仅仅涉及到阙值范围和个人偏向。
//当使用>时,阙值范围为自然数(可以为0)
//当使用>=时,阙值范围为正数(不可以为0)

水位作用(也就是阙值作用)

------水位作用:根据需要设置读写频率。(待思考)
假设有一个碗,可吃可盛。
有两种极端吃盛方式
对于吃
一种是有一点饭就吃;
一种是饭满才吃。
对于盛也是
一种是碗空一点就盛;
一种是碗全空才盛。
生活中大概都不喜欢极端方式。我一般吃的时候喜欢盛大半碗,不过回碗的时候倒是吃完再回。
但技术无所谓,技术只有适合不适合而已。
我们可以根据需要设置读写频率。(待思考,并不是频率,而是门槛)
阙值低,读写频率高,一次读写少。
阙值高,读写频率少,一次读写多。
根据需要寻找合适的阙值取值。

------水位作用:提高门槛
读:提高读取门槛 数据<阙值是不读的。 可读门槛
写:提高写入门槛 可用空间<阙值是不写的 不可写门槛

设有一个茶杯,一开始是空杯子。两个操作:喝水和倒水
喝水要根据水多少
倒水要根据空地方多少
设置阙值
水>阙值 喝水
水<阙值 不喝
空地方>阙值 倒水
空地方<阙值 不倒
阙值高,喝水的门槛增加,倒水门槛增加。
例如
喝水门槛原先是30,此时假设水量40,就可以喝,现提高到50,则40的水就不能喝;
倒水门槛原先是30,此时假设空地方是40,就可以写入,现提高到50,则40的空地方就不能写。
现在就是水量>阙值 就可以读。
可用空间>阙值就可以写。
但是注意,你并不知道水量和可用空间的具体大小,你只知道他们>阙值。
但是读的话可以知道,因为可以全部读出来,但写的话却不知道。

TCP连接缓冲区可读可写(暂写,把文章先记下来写epoll吧)

------我们设tcp连接为tcp
class tcp{
 buff
};
此时tcp连接缓冲区为tcp.buff。你可以把他看作是继承,也可以把他看作是tcp的成员。但总之tcp.buff的可读可写 应该为 缓冲区可读可写 再加上 tcp连接可读可写。

if(可读)
	tcp.buff.read();
if(可写)
	tcp.buff.write();

tcp连接可读可写
1.tcp连接关闭
当一个套接字读关闭或当一个套接字写关闭
  读关闭
  写关闭
2.tcp连接请求
3.读写错误

3.关于tcp和tcp连接的误扰

其实也就是第一个问题,tcp缓冲区应该是一个数据缓冲区,那么fin报和syn用不用写到里面。?

4.为什么需要监听套接字

5.epoll

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值