Socket for Linux Network Programming (6): Use the Recv and readn functions to implement the Readline Function

Source: Internet
Author: User

In the previous article, we implemented a readn function to read fixed bytes of data to avoid the problem of sticking packets. If the length of each field in the application layer protocol is fixed, it is very convenient to use readn for reading. For example, a protocol for uploading files on the client is designed. The first 12 bytes indicate the file name, and the file names exceeding 12 bytes are truncated. The file names below 12 bytes are supplemented with '\ 0, the file content starts from 13th bytes. After uploading all the file content, close the connection. The server can call readn to read 12 bytes and create a file based on the file name, then, read the file content and save the disk in a loop. The condition at the end of the loop is that read returns 0.

Protocols with fixed field lengths are often not flexible enough to adapt to new changes. The fields of the TFTP protocol mentioned above are variable-length, with the separator '\ 0'. The file name can be any length. Then, let's look at several option fields such as blksize, the tftp protocol does not specify that the value from the MTH byte to the nth byte is the value of blksize, the option description "blksize" is combined with its value "512" to form a variable length field.

Therefore, common application-layer protocols all contain variable-length fields. The separators between fields use line breaks '\ n', which is more common than' \ 0', such as HTTP protocol. It is inconvenient to use readn to read the variable long field protocol. Therefore, we implement a Readline function similar to fgets.

First, let's look at a system function Recv similar to read.

# Include <sys/types. h>
# Include <sys/socket. h>
Ssize_t Recv (INT sockfd, void * Buf, size_t Len, int flags );

The Recv function is similar to the READ function, but can only read socket descriptors, rather than general file descriptors, with one additional flag parameter.

The flags parameter has two important parameters: MSG_OOB, which is the option for reading out-of-band data. The TCP Header has a 16-bit emergency pointer value. The other is msg_peek, that is, data is returned from the buffer but the buffer is not cleared. This is different from read.

The following uses the encapsulated Recv function to implement the Readline function:

C ++ code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* Recv () can only read and write sockets, rather than general file descriptors */
Ssize_t recv_peek (INT sockfd, void * Buf, size_t Len)
{
While (1)
{

Int ret = Recv (sockfd, Buf, Len, msg_peek); // the buffer is not cleared after the flag is read.
If (ret =-1 & errno = eintr)
Continue;
Return ret;
}
}

/* Return if '\ n' is read, and a row can contain a maximum of maxline characters */
Ssize_t Readline (INT sockfd, void * Buf, size_t maxline)
{
Int ret;
Int nread;
Char * bufp = Buf;
Int nleft = maxline;
Int COUNT = 0;

While (1)
{
Ret = recv_peek (sockfd, bufp, nleft );
If (Ret <0)
Return ret; // If the returned value is smaller than 0, the operation fails.
Else if (ret = 0)
Return ret; // If 0 is returned, the connection is closed.

Nread = ret;
Int I;
For (I = 0; I <nread; I ++)
{
If (bufp [I] = '\ n ')
{
Ret = readn (sockfd, bufp, I + 1 );
If (Ret! = I + 1)
Exit (exit_failure );

Return ret + count;
}
}
If (nread> nleft)
Exit (exit_failure );
Nleft-= nread;
Ret = readn (sockfd, bufp, nread );
If (Ret! = Nread)
Exit (exit_failure );

Bufp + = nread;
Count + = nread;
}

Return-1;

In the Readline function, we first peat the number of characters in the buffer zone and then check whether the linefeed '\ n' exists. If so, we can use readn to connect to the linefeed to read it together, if the bufp does not exist, read the preceding data into the bufp and move the location of the bufp to the beginning of the while loop, when we call readn to read data, the buffer will be cleared, because readn calls the READ function. Note that, if '\ n' is read for the second time, count is used to save the number of characters read for the first time, and the returned RET must be added with the original data size.


Using the Readline function can also be considered as a solution to the problem of sticking to the package, that is, ending with '\ n' as a message. For the server side, you can change the do_service function based on the previous fork program as follows:

C ++ code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Void do_echoser (INT conn)
{
Char recvbuf [1024];
While (1)
{
Memset (recvbuf, 0, sizeof (recvbuf ));
Int ret = Readline (Conn, recvbuf, 1024 );
If (ret =-1)
Err_exit ("Readline error ");
Else if (ret = 0) // disable the client
{
Printf ("client close \ n ");
Break;
}

Fputs (recvbuf, stdout );
Writen (Conn, recvbuf, strlen (recvbuf ));
}
}

The client changes are similar. I will not repeat them again, and the test output is also normal.

Refer:

Linux C Programming one-stop learning

Chapter 1 TCP/IP details

UNP

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.