[Go]-use write\send to send datagrams under Linux Eagain:resource temporarily unavailable error

Source: Internet
Author: User
Tags closure set socket


Using Write\send to send datagrams Eagain:resource temporarily unavailable error under Linux

First of all, I set the socket to asynchronous, and then when I use write to send data, the way is to loop a large amount of data, because it is asynchronous, Write\send will send the data submitted to the send buffer is immediately returned, do not need to confirm the data received. In this case, it is quite possible that the send buffer is filled up, causing the write\send to no longer commit the data to be sent to the buffer. So there is the resource temporarily unavailable error, Eagain meaning is also obvious, is to you try again.

Modify the sending section as follows

[CPP] View PlainCopy
  1. int seansend (int fd, void *buffer, int length)
  2. {
  3. int bytes_left;
  4. int written_bytes;
  5. Char *ptr;
  6. ptr= (char *) buffer;
  7. Bytes_left=length;
  8. While (bytes_left>0)
  9. {
  10. / * Start writing * /
  11. Written_bytes=write (FD, PTR, bytes_left);
  12. if (written_bytes<=0)/ * ERROR has occurred * /
  13. {
  14. if (ERRNO==EINTR)/ * Interrupt Error We continue to write * /
  15. {
  16. continue;
  17. printf ("[Seansend]error errno==eintr continue\n");
  18. }
  19. Else if (errno==eagain)/ * Eagain:resource temporarily unavailable*/
  20. {
  21. Sleep (1); //Wait one second for the send buffer to be released
  22. continue;
  23. printf ("[Seansend]error errno==eagain continue\n");
  24. }
  25. Else/ * Other errors there is no way, had to retreat * /
  26. {
  27. printf ("[Seansend]error:errno =%d, strerror =%s \ n" )
  28. , errno, Strerror (errno));
  29. return (-1);
  30. }
  31. }
  32. Bytes_left-=written_bytes;
  33. Ptr+=written_bytes; / * Continue writing from the rest of the place?? * /
  34. }
  35. return length;
  36. }
A summary of non-blocking socket programming problems

Http://blog.sina.com.cn/s/blog_4462f8560100tvu4.html


The project needs to write a client program that actively connects and periodically sends the data, and guarantees the reliability and stability of the transmitted data.

The following issues are noted:

1.connect return Value Determination

Before the program

if (Connect (Tcp_client_sock, (structsockaddr*) &server, server_length) <0)

Initiate a connection to the server, Client_socket represents a socket connection for the client and the server after the connection is successful
{
printf ("Can not Connect to%s!\n", serve_ip);
Close (Tcp_client_sock);

return-1;
Exit (1);
}
Else
{
Tcp_connet_flag = 1;//Establish connection

...

}

But in the online query found: When we are in a non-blocking way to connect, the results returned if 1, this does not mean that the connection has an error, if its return result is einprogress, then the connection is still in progress. Later, you can determine whether the socket is writable by poll or select, and if it can be written, the connection is complete.

The changes are as follows:

First position as non-blocking mode, return status immediately, if error is saved as So_error value

if (Flags =fcntl (TCP_CLIENT_SOCK,F_GETFL, 0)) < 0)
{
Perror ("Fcntl");
return-1;
}
Flags |= O_nonblock;
if (Fcntl (Tcp_client_sock, F_SETFL, Flags) < 0)//Set socket to non-blocking mode
{
Perror ("Fcntl");
return-1;
}

if (Connect (Tcp_client_sock, (structsockaddr*) &server, server_length) <0)//Initiate a connection to the server
{

if (errno! = einprogress)//non-wait state
{
Perror ("Connect error");

Close (tcp_client_sock);//Next re-connect

return-1;
}
Else//einprogress: Normal processing connection
{

Perror ("Connect");//Query error value
printf ("Check delay connected\n");
Goto done;//Further check if the handshake is complete
}
}

Else
{
Done

...//Next Select to determine if Connect is complete and tcp_client_sock writable

}

Here, the perror ("connect") statement queries the error value "Operation now inprogress", indicating that the non-blocking connect immediately returns a state of three handshake being established, and if you do not want this to happen, The above statement about the non-blocking set socket can be placed in connect and will wait for connect to complete in blocking mode, but still need to be checked further. For non-blocking, the next step is to select a custom time-out (typically shorter than the Connect timeout in blocking mode) and further check for connection errors and the time-of-day socket interface read-write.

2.select Timeout Setting issue

If you set up connect as a non-blocking function, only focus on Writefds when making a select, ignoring Readfds,exceptfds, there may be a problem: you would not want to because of the connect blocking wait too long, the result with a select after the silly wait.

If you start select after Connect, only focus on Writefds, set the timeout is 10 seconds after connect issue [SYN]: Assuming that the target IP host does not exist or the target port to the firewall filter, then you wait for a long time will not have any reply, At this point it may take 15 seconds for the blocking connect to return, then you return in 10 seconds, and this will make 5 seconds.

However, assuming that the destination IP host of Connect is present and there is no firewall, only the port is not open, after the [SYN] 1 seconds The system has received the target host reply [Rst,ack], which means that the system now knows that the port is not connected, But the application only focuses on Writefds, and the next 9 seconds Select will be silly to wait ... Originally thought to use Select to reduce unnecessary wait time, if do not set the parameter Exceptfds, this time instead of wasting.

3.SEND/RECV return value

Because the send, recv function is used for a connected datagram or a stream socket interface s for data reception. Therefore, in the non-blocking socket client program recv, the Send function returns does not mean that the peer must have received the message sent. The TCP protocol itself is reliable and does not mean that the application will be reliable when it sends data over TCP. The size of send sent, regardless of whether it is blocked, does not represent the amount of data recv to the end.

About recv return value, Baidu's explanation:

1). If no error occurs, recv () returns the number of bytes read in.

2). Returns 0 if the connection is aborted.

3). Otherwise, return socket_error error.

If the socket is of type sock_stream and the remote "gracefully" aborts the connection, then recv () does not read the data and returns immediately. If it is forcibly aborted immediately, then recv () will return with a Wsaeconnreset error failure.

When receiving data perror often encounter "Resource temporarilyunavailable" prompt, errno code is one (Eagain). This indicates that you have a blocking operation in non-blocking mode, which returns the error if the operation is not completed, which does not break the synchronization of the socket, regardless of the next loop and then recv. For non-blocking sockets, Eagain is not an error. On VxWorks and Windows, Eagain is named Ewouldblock. In fact, this is not a mistake, just an anomaly.

In addition, if EINTR is present as errno is 4, the error describes interrupted Systemcall, which means that the operation failed due to a signal interruption and should continue.

Val= recv (client_sock,info,length,msg_nosignal);
if (val< 0)//Determine if the network has no data or whether the receive buffer is ready
{
if (val==eagain| | ewouldblock| | EINTR)
{
printf ("RecvData timeout.waiting...\n");
RETURN1;
}
else//network abnormally disconnected or blocked; reconnect required
{
Perror ("recv");
return-1;
}
}

ElseIf (val = = 0)//server End normally closed, need to reconnect

{

tcp_connet_flag=0;//closing the TCP connection FLAG
printf ("Socketclose nomally\n");
Return0;
}

else//return received bytes greater than 0, normal receive data
{

//Read and write processing for each byte of receive buffer info

return 1;

}

About the difference between the Send function in blocking mode and non-blocking mode:

In blocking mode, the Send function is copied from the data sent by the application request to the send cache and then returned. However, due to the presence of the send cache, the Send function returns immediately and sends data to the network if the sending cache size is larger than the size of the request sent; Send sends a portion of the data that the cache cannot hold in the network, waits for the peer to confirm and then returns (the receiving end will confirm that it is not necessarily waiting for the application to call recv) as long as it receives the data in the receive cache;
In non-blocking mode, the Send function is simply copying the data to the buffer of the protocol stack, if the buffer space is not available enough, then the ability to copy, return the size of the successful copy, if the buffer free space is 0, then return 1, and set errno to Eagain.

When a customer sends a large packet via the Send function provided by the socket, a eggain error may be returned. This error occurs because the size variable in the Send function exceeds the value of Tcp_sendspace. Tcp_sendspace defines the amount of data that an app can cache in kernel before calling send. When the application sets the O_ndelay or O_nonblock property in the socket, send returns a eagain error if the sending cache is full.

1). Increase Tcp_sendspace, Make it larger than the size parameter in send
---no-p-otcp_sendspace=65536
2). Set a larger value for SNDBUF in the SetSockOpt function before calling send

INTOPT=SO_REUSEADDR;
SetSockOpt (tcp_client_sock,sol_socket,so_reuseaddr,&opt,sizeof (opt));
opt = 256*1024;//512k
int optlen = sizeof (int);
setsockopt (tcp_client_sock,sol_socket,so_sndbuf,&opt,sizeof (int));
GetSockOpt (Tcp_client_sock,sol_socket,so_sndbuf,&opt,&optlen);
3). Use write instead of send because write is not set O_ndelay or O_nonblock

In Csdn, you see a situation like this:

If the sender traffic is larger than the traffic at the receiving end (meaning that the Epoll program reads faster than the forwarded socket), the Send () function returns, but the actual buffer data is not actually sent to the receiving end, as the non-blocking socket, A eagain error occurs when the buffer is full, ignoring the data sent by this request.

Therefore, you need to follow the Send () function return value and errno value for further processing. When this occurs, the function requires that the data be written back as much as possible, or by changing the send buffer size. When the write buffer is full (send () returns-1, and errno is Eagain), then the Send () is waited and retried. This is not a perfect way, and in theory it can be blocked in the socket's send (), but there is no better way.

sendflag&=tcp_connet_flag;//Test Tcp_client_sock Descriptor writable and TCP connection present
if (sendflag==1)//try to send
{
Res=send_client_info (tcp_client_sock,buf,45);
if (res<0)
{
if (errno = = eintr)//When the socket is non-blocking, such as returning this error, indicates that the write buffer queue is full and returns to determine the network status and retry.
return-1;
if (errno = = eagain)//Send buffer remaining 0 bytes, delay waiting to send;
{
Usleep (10000);
Res=send_client_info (tcp_client_sock,buf,45);
}
}
}
Else
{
...//Send buffer data staging, wait for normal connection
}

In a Linux programming environment, if you continue to send data after the TCP connection is disconnected, not only will the return value of Send () be reflected, but it will also send an exception message like the system, and if it is not processed, the system will brokepipe and the program will exit. To do this, the last parameter of the Send () function can be set to msg_nosignal, which prevents the Send () function from sending an exception message to the system.

Problem with SEND/RECV data after 3.close (socket)

If the send () is not completed while sending the data, and the data is not sent, and the closesocket () is called, the usual action is shutdown (S,sd_both), but the data will be lost.

If the design program function requires data to be sent out before closing the socket, do the following:

struct Linger {

U_short L_onoff;

U_short L_linger;

};

Linger M_slinger;

M_slinger.l_onoff = 1;//The data is not sent when calling Closesocket (), allowing waiting

If m_slinger.l_onoff=0, force close after calling Closesocket ()

M_slinger.l_linger = 5;//Set wait time of 5 seconds

SetSockOpt (S, Sol_socket, So_linger, (const char*) &m_slinger, sizeof (LINGER));

If So_linger is set and a non-zero timeout interval is determined, closesocket () calls the blocking process until the remaining data is sent or timed out. This closure is called "graceful" closure. Note that if the socket is set to non-blocking and So_linger is set to a non-0 timeout, the closesocket () call will be returned with a wsaewouldblock error.

Wsaewouldblock: The socket is set to non-blocking mode and the So_linger is set to a non-0 timeout interval.

[Go]-use write\send to send datagrams under Linux Eagain:resource temporarily unavailable error

Related Article

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.