1. socket
对套接字编程的理解还停留在阻塞的阶段,对传输过程中的数据处理不太理解 ,请大家指点一二
但是我不确定怎么传数据好,于是想到两个办法
1.1 一块一块的发,一块一块的送
确定一个定长的char bytes[size]
,
send:
loop:
将数据一块一块拷贝进`bytes`,然后发出
recv:
loop:
将数据一块一块从对端读入,然后处理
1.2 告诉对端要发多少,在一起发出去
2.http
我记得http报文是是不定长的,那么对端是怎么知道要接收多少数据??
我特意去问了下老师,他说是用流来处理,不需要向我上面那样用定长数组一块一块处理,我不是很明白
另外
不知道套接字编程的时候需不需要封装字节流,这是我的想法
我想做一个buffer
封装要发送或接收的数据
struct buffer {
unique_ptr<char> data;
....
};
http两种处理方式:1. buffer,读到两个空行位置。2. content-length 指明长度。
一般自己直接使用长链接的话,会先传长度。
如果你问的是底层是不是一块一块的传输的,答案是:是。
如果你问的是需不需要每次write都添加一个自定义长度头,答案是:否。
guo
5
上面几个回复都没有说道点子上。
TCP传输数据的概念并不是“块”,而是“流”
一个TCP连接就是一个管子,发送放向管子里面塞数据,接收方从管子里面取数据。
发送方不能假设一定能把数据发送出去,因为管子可能会都塞。所以send函数的返回值是这次发出去了几个字节。
接收方也不能假设每次收到的数据大小和发送方是对应的块。因为在传输过程中可能会重新打包数据。
你的1.1/1.2是常用的处理数据边界的方法。
http用的不是你上面说的这两种,而是其它方法:
- content-length
- chunked transfer encoding
另外,tcp是字节流,每次能发出去多少/接收到多少不完全决定于你bytes的长度。所以你1.1里不能保证一次把size长的数据都发出去,接收端也不一定一次就正好接收到size长的数据。
EDIT: 你最后的问题,从tcp层面来说,不一定需要封装。
流只是一个虚拟的概念,管子也是。加深理解可以,回答具体问题还是别了。别误导别人。
比如:每次数据包经过的节点是一样的么?
tcp做应用层数据传输一般需要应用自己分包,分包的方法有三个:
1 按照(长度+数据)(长度+数据)的方式发送
2 像http那样使用特殊字符分包,比如两个换行算一个包的结束,但数据需要编码(base64等)
3 一个连接传一包,通过断链代表一包发送完成,这个见得比较少,但也不是没有。
- TCP 的话 client 调用 close 就会正常关闭 socket 了,或者异常情况下关闭 socket
- 网络协议本身规定了如何解析本协议的报文,哪里开始,哪里结束,你只要按照协议标准解析字节流就行了
“流”(stream)是一种抽象,这样对使用 Socket 的用户就不用关心 TCP 协议的通信细节了,只要知道 bind_address/send/recv/close 就行了,对用户来说,他们操作的是“流”。
其实我不怎么明白,在阻塞条件下怎么传输大数据,是直接传呢还是一块一块传
流又是怎么做的??
// client
for data in big_data {
client_skt.send(data);
}
client_skt.close();
// server
loop {
data = server_skt.recv(); // blocking
handle_data(data);
}
是一块一块传的啊,还是我说的抽象层次的问题。本质上所有的数据都是离散传输的,哪里有“真正的连续”?链路层,传输层都是一个一个的数据包,说“流”就是为了让用户忽略这些细节。
xlshiz
15
udp使用也不用关心细节,但它不是流。流是一种抽象,但需要协议实实在在的实现它,对于tcp协议,直白的说就是协议里边没有长度字段,udp有长度字段。
对于大数据(Linux小于0x7ffff000)的发送,阻塞模式,tcp可以一次write直接全部发送,也可以拆包循环发送,最大值由操作系统限制。对于udp,一次最大发送64k,最大值由协议限制。
1 个赞
xlshiz
16
应用层数据包,tcp数据流,udp报,ip包,tcp包,再加上ip分片,是比较容易绕晕。
如果你说tcp连接是个管子,那么你这里就是在暗示楼主连接一经建立所有包经过的节点的ip是一样的。但是其实是动态的。所以不要使用一些虚拟的带比喻概念的来描述一个事实。
感谢纠正,udp 不是很了解。
tcp可以一次write直接全部发送
你说的一次发送全部数据只是上层接口设计成这样,实现仍然是“切成小块循环发送”,比如 Python 提供的 send 和 send_all,send_all 底层仍然是循环调用 send。
更准确的说,能不能一次发完,取决于数据是不是真的所谓的“大块”数据
posix send: https://linux.die.net/man/3/send
If the message is too long to pass through the underlying protocol, send () shall fail and no data shall be transmitted.
linux send 的实现 https://linux.die.net/man/2/send
The maximum control buffer length the kernel can process is limited per socket by the value in /proc/sys/net/core/optmem_max ;
robinx
20
你说的是IP层的问题,我理解TCP层面上不需要关注这个。