歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux服務器

Linux下使用TCP通訊時遇到的問題

在這裡總結一下這linux用TCP通訊需要注意的幾個問題,都是前一陣子工作中遇到的問題。

    問題1. 發送和接收數據時的不完整問題

    以接收為例,當對端發送1000個字節的數據時,本端進行接收,會出現調用recv返回500並且errno==EAGAIN的情況(測試中發現這種情況非常嚴重),這個錯誤表示當前設備忙,稍後再試。理想化的解決辦法是這樣的:

    使用select或者epoll機制,當有數據到來時,select或epoll會通知,此時一直接收直到recv返回0表示所有數據都接收完。過程中當errno==EAGAIN則暫停接收,並將已經接收的數據緩存起來。當設備再次可讀時select或者epoll會再次通知,在緩存數據的後面繼續接收,如此反復n次直到recv返回值為0。

    但是這種方法需要把已經接收的部分數據進行緩存,實現起來非常繁瑣,我進行了如下的簡單實現,是我封裝的epoll中的部分代碼:

     int
mo_epoll_recv (int s, void* buf, int buf_size, int err)
{
int recved_len = 0;
int total_recv_len = 0;
int count = 0;

if (buf == NULL || buf_size <= 0)
{
return -1;
}

MO_DEBUG ("to recv some data!\n");

do
{
//MO_DEBUG ("call recv, total_recv_len=%d recv_len=%d\n", total_recv_len, buf_size-total_recv_len);
recved_len = recv (s, buf+total_recv_len, buf_size-total_recv_len, err);

//MO_DEBUG ("called recv, recved_len=%d\n, errno=%d:EAGAIN=%d:%s\n", recved_len, errno, EAGAIN, strerror (errno));

if (recved_len < 0 && errno != EAGAIN)
{
MO_ERROR ("some error when recv erron: %d, %s", errno, strerror (errno));
break;
}
else if (recved_len < 0 && errno == EAGAIN)
{
recved_len = 1;
/* 10s timeout */
if (++count > 200)
{
break;
}
usleep (1000*50);
continue;
}
total_recv_len += recved_len;
if (total_recv_len >= buf_size)
{
recved_len = 0;
//MO_DEBUG ("recv %d bytes!!!!!", total_recv_len);
break;
}
usleep (1000*50);
}while(recved_len > 0);
MO_DEBUG ("recv some data over %d bytes!\n", total_recv_len);

if (recved_len == -1)
return -1;

return total_recv_len;
}
int
mo_epoll_send (int s, const void* buf, int buf_size, int err)
{
int sended_len = 0;
int total_send_len = 0;

if (buf == NULL || buf_size <= 0)
{
return -1;
}
MO_DEBUG ("to send some data!\n");

do
{
sended_len = send (s, (buf+total_send_len), buf_size-total_send_len, err);
if (sended_len == -1 && errno != EAGAIN)
{
break;
}
else if (sended_len == -1 && errno == EAGAIN)
{
sended_len = 1;
continue;
}
total_send_len += sended_len;
if (total_send_len >= buf_size)
{
sended_len = 0;
//MO_DEBUG ("send %d bytes!!!!!", total_send_len);
break;
}
}while(sended_len > 0);
MO_DEBUG ("send some data over %d bytes!\n", total_send_len);

if (sended_len == -1)
return -1;

return total_send_len;
}


    問題2. 干淨的關閉socket,應該使用如下方法來關閉你不使用的socket,不要僅僅調用close():

     cleanclose (int s)
{
int i = 0;
char buf[100];
/* 關閉寫入 */
shutdown (s, SHUT_WR);
/* 接收所有數據 */
do
{
i = recv (s, buf, 100, 0);
}while (i > 0);
/* 關閉讀取 */
shutdown (s, SHUT_RD);

/* 關閉socket */
close (s);
}

Copyright © Linux教程網 All Rights Reserved