C 获取套接字读取操作的进度

C 获取套接字读取操作的进度,c,sockets,posix,C,Sockets,Posix,我想用C写一个小文件传输程序(我在Linux上工作)。 我对sockets编程相当陌生,但我已经设法编写了一些服务器和应用程序 客户端程序 我的问题: 如果我有这样的东西: int read_bytes=read(socket_id,buffer,4096) 从插座读取时,如何获得读取进度? 例如,我想每100ms显示传输了多少字节 目前为止我很确定我必须在这里使用线程或其他异步函数。 是否有一个函数可以让我获得读取的字节数和读取的字节数 更新1: 累加读取() 这不是非常非常低效吗?(例如,传

我想用C写一个小文件传输程序(我在Linux上工作)。 我对sockets编程相当陌生,但我已经设法编写了一些服务器和应用程序 客户端程序

我的问题:

如果我有这样的东西:

int read_bytes=read(socket_id,buffer,4096)

从插座读取时,如何获得读取进度? 例如,我想每100ms显示传输了多少字节 目前为止我很确定我必须在这里使用线程或其他异步函数。 是否有一个函数可以让我获得读取的
字节数
和读取的
字节数

更新1: 累加读取()

这不是非常非常低效吗?(例如,传输1MiB文件)


谢谢你

如果你可以控制服务器和客户端的代码,你可以让发送者在实际发送文件之前告诉接收者文件的大小。例如,使用消息中的前8个字节。这是要读取的
字节数


通过累积示例中的
read_字节
,您可以获得
读取的字节数

每个
recv
调用将阻塞,直到读取更多字节,但它不会(默认情况下/sans
MSG_WAITALL
)等待提供的缓冲区满。这意味着不需要为了更频繁地更新总字节读取信息而减少缓冲区大小,您可以轻松地保留总的
recv()
返回值,这些值在数据包到达时更新(或者以应用程序可以从操作系统缓冲区处理它们的速度更新)

正如您所观察到的,如果该总数每秒更新100次,您可能不想发布100次屏幕更新,而是将它们限制在100ms-min的间隔内。您可以使用计时器/警报来管理它,但是您有更多的边缘情况来查看计时器是否已经挂起等。。仅使用两个线程可能更简单,其中一个线程定期检查是否需要更新:

  • 线程1:
    • 而((n_字节=recv(…)>0)
      • 总字节数+=n字节
    • 设置屏幕更新程序终止标志
  • 线程2:
    • 最后的字节总数=-1
    • 而屏幕更新程序终止标志未设置
      • 睡眠100毫秒
      • 如果最后\u个字节总数!=总字节数
        • 更新屏幕
        • 最后\u总计\u字节=总计\u字节
当然,您需要使用互斥或原子操作来协调这些操作

有没有一个函数可以让我得到。。。要读取的字节数


不是来自TCP本身——它没有消息大小的概念,API只是确保应用程序按照发送字节的相同顺序接收字节。如果您希望能够显示“到目前为止收到的N个字节,预期的X个字节”,那么在应用程序协议级别,发送端应在逻辑消息中为数据加上前缀,前缀的大小通常为固定宽度的二进制格式(理想情况下,在recv端使用
htonl
或类似的send和
ntohl
,以避免endian问题),或使用文本表示,该文本表示由已知的哨兵字符(例如NUL、空格或换行符)固定或与数据分离.

您将需要计算从每次调用
read/reicv
读取的字节数,并报告所需的总字节数。您可以使用较小的缓冲区大小对读取进行粒度化。这将根据情况而定。如果使套接字不可用,则可以跳过使用线程-blocking@Asaf:这对我们来说是不必要的e如给定的要求,当没有数据时,让recv立即返回不是需要更新屏幕总数的情况。Krumia的建议也没有帮助,因为recv将返回(默认情况下)当一些数据已被传递,而不阻止更多的网络到达。@ PTEXX:该代码将在非阻塞模式下烧毁CPU,但通常在阻塞模式下是有效的(您可能会考虑更大的缓冲区大小-例如16K -但是一般的循环和逻辑是好的)。,但终止需要是
read_bytes>0
,才能处理-1错误返回值。你说的“累加”到底是什么意思?你是说调用read()吗在循环中?@pentix:不管你想怎样:在循环中,作为类成员变量,etc不需要引入多个线程或计时器/警报来限制屏幕更新的发送速率。相反,当recv()返回时,只需检查当前时间(通过clock_gettime()的times()或其他毫秒或更高分辨率的时钟API)查看自上次触发屏幕更新以来是否已超过100毫秒。如果是,请触发另一次屏幕更新;否则不要。+1用于提及
htonl
的需要。我忘记了网络字节顺序。@JeremyFriesner:错-假设第二次
recv
在第一次之后返回50毫秒,在第三次之后返回10秒r使用您的方法,第二个
recv
读取的字节不会立即出现在屏幕上,因为从第一个开始到现在还不到100毫秒,只有第三个
recv
会让事情回到正轨。使用TCP时,可能会出现突然峰值,因为丢失或延迟的数据包会使较早接收到但随后排序数据包将被
recv
-ed。在这些问题上真正的准确性是否有用是有争议的,但这正是问题所要求的……@TonyD所以我们一致认为,如果你不需要完美的准确性,它会起作用。如果你确实需要完美的准确性,你可以通过使用select()来获得有一个超时参数和非阻塞I/O。@JeremyFriesner:这不是“完美的准确性”-根据问题,它是100毫秒的更新,对于一些人来说,“我可能会以不确定的数量显示过时的数据。”
int total_read_bytes=0, read_bytes;
char buffer[4096];
do {
    read_bytes = read(socket_id, buffer, 4096);
    total_read_bytes += read_bytes;
} while(read_bytes > 0); /* Read to end or read failed */