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

來源:互聯網
上載者:User
在這裡總結一下這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():

void
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);
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.