Unix Network Programming Episode 92

本文介绍了在socket编程中查看接收队列数据的不同方法,如非阻塞I/O、使用MSG_PEEK标志以及通过ioctl的FIONREAD命令。同时讨论了标准I/O库在处理socket输入输出时的缓冲问题及其解决策略。
摘要由CSDN通过智能技术生成

The difference between CMSG_LEN and CMSG_SPACE is that the former does not account for any padding following the data portion of the ancillary data object and is therefore the value to store in cmsg_len, while the latter accounts for the padding at the end and is therefore the value to use if dynamically allocating space for the ancillary data object.

How Much Data Is Queued?

There are times when we want to see how much data is queued to be read on a socket, without reading the data. Three techniques are available:

1.If the goal is not to block in the kernel because we have something else to do when nothing is ready to be read, nonblocking I/O can be used.
2.If we want to examine the data but still leave it on the receive queue for some other part of our process to read, we can use the MSG_PEEK flag (Figure 14.6(See 9.3.3)). If we want to do this, but we are not sure that something is ready to be read, we can use this flag with a nonblocking socket or combine this flag with the MSG_DONTWAIT flag.
3.Some implementations support the FIONREAD command of ioctl. The third argument to ioctl is a pointer to an integer, and the value returned in that integer is the current number of bytes on the socket’s receive queue (p. 553 of TCPv2). This value is the total number of bytes queued, which for a UDP socket includes all queued datagrams. Also be aware that the count returned for a UDP socket by Berkeley-derived implementations includes the space required for the socket address structure containing the sender’s IP address and port for each datagram (16 bytes for IPv4; 24 bytes for IPv6).

Sockets and Standard I/O

In all our examples so far, we have used what is sometimes called Unix I/O, the read and write functions and their variants (recv, send, etc.). These functions work with descriptors and are normally implemented as system calls within the Unix kernel.

Another method of performing I/O is the standard I/O library. It is specified by the ANSI C standard and is intended to be portable to non-Unix systems that support ANSI C. The standard I/O library handles some of the details that we must worry about ourselves when using the Unix I/O functions, such as automatically buffering the input and output streams. Unfortunately, its handling of a stream’s buffering can present a new set of problems we must worry about. Chapter 5 of APUE covers the standard I/O library in detail, and [Plauger 1992] presents and discusses a complete implementation of the standard I/O library.

The standard I/O library can be used with sockets, but there are a few items to consider:

  • A standard I/O stream can be created from any descriptor by calling the fdopen function. Similarly, given a standard I/O stream, we can obtain the corresponding descriptor by calling fileno. Our first encounter with fileno was in Figure 6.9(See 8.4.4) when we wanted to call select on a standard I/O stream. select works only with descriptors, so we had to obtain the descriptor for the standard I/O stream.
  • TCP and UDP sockets are full-duplex. Standard I/O streams can also be full-duplex: we just open the stream with a type of r+, which means read-write. But on such a stream, an output function cannot be followed by an input function without an intervening call to fflush, fseek, fsetpos, or rewind. Similarly, an input function cannot be followed by an output function without an intervening call to fseek, fsetpos, or rewind, unless the input function encounters an EOF. The problem with these latter three functions is that they all call lseek, which fails on a socket.
  • The easiest way to handle this read-write problem is to open two standard I/O streams for a given socket: one for reading and one for writing.
#include "unp.h"

void str_echo(int sockfd)
{
    char line[MAXLINE];
    FILE *fpin, *fpout;
    fpin=Fdopen(sockfd, "r");
    fpout=Fopen(sockfd, "w");

    while(Fgets(line, MAXLINE, fpin)!=NULL)
        Fputs(line, fpout);
}

str_echo function recoded to use standard I/O

There is a buffering problem here because nothing is echoed by the server until we enter our EOF character. The following steps take place:

  • We type the first line of input and it is sent to the server.
  • The server reads the line with fgets and echoes it with fputs.
  • The server’s standard I/O stream is fully buffered by the standard I/O library.

This means the library copies the echoed line into its standard I/O buffer for this stream, but does not write the buffer to the descriptor, because the buffer is not full.

  • We type the second line of input and it is sent to the server.
  • The server reads the line with fgets and echoes it with fputs.
  • Again, the server’s standard I/O library just copies the line into its buffer, but does not write the buffer because it is still not full.
  • The same scenario happens with the third line of input that we enter.
  • We type our EOF character, and our str_cli function (Figure 6.13(See 8.4.7)) calls shutdown, sending a FIN to the server.
  • The server TCP receives the FIN, which fgets reads, causing fgets to return a null pointer.
  • The str_echo function returns to the server main function (Figure 5.12(See 8.3.10)) and the child terminates by calling exit.
  • The C library function exit calls the standard I/O cleanup function (pp. 162–164 of APUE). The output buffer that was partially filled by our calls to fputs is now output.
  • The server child process terminates, causing its connected socket to be closed, sending a FIN to the client, completing the TCP four-packet termination sequence.
  • The three echoed lines are received by our str_cli function and output.
  • str_cli then receives an EOF on its socket, and the client terminates.
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值