1. 程式人生 > >C++ TCP socket程式設計中的小陷阱(服務端accept 不阻塞 和 客戶端connect 重連失敗)

C++ TCP socket程式設計中的小陷阱(服務端accept 不阻塞 和 客戶端connect 重連失敗)

在編寫一個使用C++ socket實現的TCP服務端與客戶端小軟體時接連碰上2個小陷阱,

終歸是實踐不足,基本功不紮實。

第1個問題: 服務端的accept函式沒有阻塞

    程式執行到accept這裡時直接就跳了過去,根本沒停下來。

    懷疑過socket的配置是否有錯誤,經過各種除錯,當把socket部分的程式碼從工程中截取出,單獨放到一個空白工程中執行時,一切又都正常了。

    證實了socket的配置沒有問題,只能是原工程中的哪個標頭檔案包含後把socket的函式覆蓋了。

    又經過了幾次試驗,最終定位到了罪魁禍首竟然是using namespace std

    網上查了一下才知道原來這也是個常見問題。因為std的名稱空間裡包含了太多常用的函式名,當全域性使用std名稱空間時,很容易發生函式執行沒有得到預期的效果。

    在socket的這個問題中,重要的bind函式被std中的同名函式覆蓋,使得服務端的socket沒有繫結ip地址和商品,自然之後的accept函式也就不能正常阻塞。

     對策有2種,

     1是把bind函式改為全域性呼叫方式  ::bind(), 擺脫std名稱空間的影響。 

     2是放棄std名稱空間在全域性範圍內的宣告,改用指定使用函式的方式。 如 using std::cout 或using std::endl

第2個問題:客戶端socket斷開後重連失敗

    這是在測試的時候發現的問題。這次的小軟體設計是客戶端在與服務端保持TCP連線的過程中可以隨意向服務端傳送命令。操作結束後可以暫時斷開TCP連線,當有需求時再次連線。

    因此客戶端的處理框架是迴圈等待使用者輸入,再根據內容來判斷需要向服務端發起什麼樣的操作請求。

  WORD wVersionRequested;
  WSADATA wsaData;
  int err;
  SOCKET sockClient;

  wVersionRequested = MAKEWORD(1, 1);

  err = WSAStartup(wVersionRequested, &wsaData);
  if (err != 0) {
    return;
  }

  if (LOBYTE(wsaData.wVersion) != 1 ||
    HIBYTE(wsaData.wVersion) != 1) {
    WSACleanup();
    return;
  }
  sockClient = socket(AF_INET, SOCK_STREAM, 0);

  SOCKADDR_IN addrSrv;

  inet_pton(AF_INET, "127.0.0.1", &addrSrv.sin_addr.s_addr);

  addrSrv.sin_family = AF_INET;
  addrSrv.sin_port = htons(6000);


  while (1)
  {
    char in_buf[40];
    string input_command;

    cin >> in_buf;

    input_command = in_buf;

    if (input_command.compare("TCP connect") == 0)
    {
      connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
      char recvBuf[500]; recv(sockClient, recvBuf, 500, 0);
      printf("%s\n", recvBuf);

    }
    else if (input_command.compare("operation") == 0)
    {
      char requst_buf[40] = "operation";
      send(sockClient, requst_buf, strlen(requst_buf) + 1, 0);

      char recvBuf[500]; recv(sockClient, recvBuf, 500, 0);
      printf("%s\n", recvBuf);
    }

    else if (input_command.compare("disconnect") == 0)
    {
      char requst_buf[40] = "disconnect";
      send(sockClient, requst_buf, strlen(requst_buf) + 1, 0);

      char recvBuf[500]; recv(sockClient, recvBuf, 500, 0);
      printf("%s\n", recvBuf);

      closesocket(sockClient);
    }
}

這樣的客戶端程式碼在啟動後第一次連線服務端時一切都很正常,但在斷開後做再次連線時發生了異常,服務端並沒有收到再連線請求,一直停留在accept阻塞的位置。而客戶端卻能收到socket的資訊反饋,但進一步確認後發現也只能收到返回訊息,需要服務端處理的操作就無法得到服務端的響應。

這個現象就像是客戶端在做二次連線時,連線請求並沒有送到服務端,而只是把客戶端可能會收到的返回訊息作為快取放在socket中,給客戶端造成一種已經再次連線上的假象。

又經過一陣網路搜尋,原來這也是一種常見現象。已經連線過的socket資源不能直接用於再次連線,要麼對它做一次初始化,要麼再次生成一個新的socket資源。作為修改,我選擇了後者。

    if (input_command.compare("TCP connect") == 0)
    {
      WORD wVersionRequested;
      WSADATA wsaData;
      int err;

      wVersionRequested = MAKEWORD(1, 1);

      err = WSAStartup(wVersionRequested, &wsaData);
      if (err != 0) {
        return;
      }

      if (LOBYTE(wsaData.wVersion) != 1 ||
        HIBYTE(wsaData.wVersion) != 1) {
        WSACleanup();
        return;
      }

      SOCKET sockClient;
      sockClient = socket(AF_INET, SOCK_STREAM, 0);

      SOCKADDR_IN addrSrv;

      inet_pton(AF_INET, "127.0.0.1", &addrSrv.sin_addr.s_addr);

      addrSrv.sin_family = AF_INET;
      addrSrv.sin_port = htons(6000);

      connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
      char recvBuf[500]; recv(sockClient, recvBuf, 500, 0);
      printf("%s\n", recvBuf);

    }

把socket的建立程式碼移到發起TCP連線時才執行,保證每次發起連線請求用的都是新的socket,問題得到解決。

相關推薦

C++ TCP socket程式設計中的小陷阱服務accept 阻塞 客戶connect 失敗

在編寫一個使用C++ socket實現的TCP服務端與客戶端小軟體時接連碰上2個小陷阱, 終歸是實踐不足,基本功不紮實。 第1個問題: 服務端的accept函式沒有阻塞     程式執行到accept這裡時直接就跳了過去,根本沒停下來。     懷疑過socket

簡單的TCP協議 socket程式設計C語言版伺服器客戶

         最近由於本人對網路程式設計的喜愛,所以對一點關於TCP協議socket程式設計的總結。由於本人的能力有限,寫的可能過於簡單,只適合初學者,歡迎大牛提出寶貴的意見,本人會感激不盡的。廢話少說了,進入正題。(下面程式碼是基於VC6.0)          下圖

Qt:Qt實現Winsock網路程式設計TCP服務客戶通訊多執行緒

Qt實現Winsock網路程式設計—TCP服務端和客戶端通訊(多執行緒) 前言 感覺Winsock網路程式設計的api其實和Linux下網路程式設計的api非常像,其實和其他程式語言的網路程式設計都差不太多。博主用Qt實現的,當然不想用黑視窗唄,有介面可以看到,由於GUI程式設計

C#程式設計 socket程式設計tcp伺服器客戶

基於Tcp協議的Socket通訊類似於B/S架構,面向連線,但不同的是伺服器端可以向客戶端主動推送訊息。 使用Tcp協議通訊需要具備以下幾個條件: (1).建立一個套接字(Socket) (2).繫結伺服器端IP地址及埠號--伺服器端 (3).利用Listen()方法開啟監聽--伺服

java socket網路程式設計例項程式碼服務客戶

本程式碼為java socket網路程式設計例項程式碼,包括客戶端和服務端,實現客戶端傳送訊息,服務端接收並反饋訊息。 server.java為服務端程式碼。 client.java為客戶端程式碼。 服務端程式碼server.java: package socket;

Windows C語言 Socket程式設計 server伺服器--初級客戶——初級版

看過我的簡單版的伺服器程式碼的,會發現那段程式碼同一時間只能和一個客戶端通訊。這樣的程式碼能力很小侷限性很大。今天我來介紹一種多客戶端的伺服器程式碼。當然這段程式碼還是有問題的,至於是什麼問題我會在程式碼後面說清楚。 我的這個多客戶端的程式碼核心思想是多執行緒

Windows C語言 Socket程式設計 client客戶--斷線

瞭解了最基礎的C語言客戶端的編寫流程,稍稍加以改動即可實現斷線重連。 當伺服器掉線時,客戶端會以固定的頻率不停的重連。 #include <stdio.h> #include <winsock2.h> #pragma comme

Socket程式設計(非同步通訊)Tcp,Udp

上一章主要展示了Socket的Tcp\Udp兩種協議下的基本通訊方式,屬於同步通訊。至於一個伺服器對應多個客戶端,或者對應多個請求,我們採用的是多執行緒的方式來解決此問題。然而本章節我們將有更好的方式去實現它:Socket在Tcp\Udp兩種協議下的非同步通訊方式。 基

MFC——socket程式設計淺出+深度:服務客戶埠問題

要寫網路程式就必須用Socket,這是程式設計師都知道的。而且,面試的時候,我們也會問對方會不會Socket程式設計?一般來說,很多人都會說,Socket程式設計基本就是listen,accept以及send,write等幾個基本的操作。是的,就跟常見的檔案操作一樣,只要寫過就一定知道。 對於網路程式設計,

C#版 Socket程式設計最簡單的Socket通訊功能

 示例程式是同步套接字程式,功能很簡單,只是客戶端發給伺服器一條資訊,伺服器向客戶端返回一條資訊;這裡只是一個簡單的示例,是一個最基本的socket程式設計流程,在接下來的文章中,會依次記錄套接字的同步和非同步,以及它們的區別。 下面是示例程式的簡單步驟說明 伺服器端:

我所知道的TCP Socket程式設計-交換資料、套接字讀寫操作

五:交換資料 已經建立了伺服器和客戶端的連結,現在需要讓它們進行資料交換;      你可以將TCP連線想象成一串連線了本地套接字和遠端套接字的管子,我們可以沿著這個管子傳送和接受資料;

Socket系列基於Socket網路通訊的服務客戶程式設計

        Socket系列一主要介紹了Socket的基礎知識、工作原理以及與傳統的http協議的區別。這部分內容的目的是為本文做鋪墊。本文將介紹基於Socket網路通訊的伺服器端和客戶端的程式設計。 一、伺服器端的程式設計         關於Socket伺服器端的

C#Socket程式設計詳解Socket程式設計

三、Socket程式設計1、UDP通訊1.1採用Socket實現UDP1.1.1簡介Socket實現UDP的基本步驟如下:(1)建立一個Socket物件Socket mySocket = new Socket(AddressFamily.InterNetwork,Socket

Linux c實現一個tcp文件服務客戶

repr snippets 功能 stderr strcpy fprintf inet_addr 編寫 create 總體需求:編寫tcp文件服務器和客戶端。客戶端可以上傳和下載文件。 ===========================================

Linux C++ TCP Socket通信實例

內容 set color 分享 int clas 打開 makefile src 環境:Linux 語言:C++ 通信方式:TCP   下面用TCP協議編寫一個簡單的服務器、客戶端,其中服務器端一直監聽本機的6666號端口。如果收到連接請求,將接收請求並接收客戶端發來的消息

Socket TCP 協議實現服務客戶的簡單通訊-結合線程池的使用

文章目錄 前言 當前模式的弊端 服務端程式碼 客戶端程式碼 執行結果 客戶端 服務端

從零開始學Socket連線服務客戶

先了解一下執行緒問題,在Main函式裡就是主執行緒他能處理程式碼,而new Thread就是新開一個執行緒,他和主執行緒互不干預,但是主執行緒完了,他也完了。他完了,主執行緒沒事。   在上篇部落格裡,我們已經建立好了伺服器端和客戶端,但是他們倆還沒有聯絡,要把他們聯絡起來,就

從零開始學Socket服務客戶建立

上篇我提到Socket是TCP/IP的抽象介面。所以我們直接使用就好,沒必要知其甚解。 1.開啟VS 新建專案 名稱,位置隨意 這裡名稱是Server 框架選.NET 4.5(在這篇部落格裡也無所謂) 注意引用 using System.Net; using

Linux下網路socket程式設計——實現伺服器select與多個客戶通訊

Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊 置頂 2017年06月23日 14:44:37 閱讀數:3225 標籤: socket程式設計伺服器與多個客戶端通epoll多路複用C語言網路程式設計 更多

C++中Socket程式設計入門

C++中Socket程式設計入門 轉載 :http://www.cnblogs.com/L-hq815/archive/2012/07/09/2583043.html 該作者也是轉載,為國外網站翻譯之作 本人在學習Socket程式設計時,在其他地方看到了不錯Socket入門文件,通俗