C++ 網絡編程 總結


第一次用C++寫程序,對C++ 只是菜鳥級別的,倒是對C#很熟悉。兩者有很大的相似性。但也有不同。

首先寫了一個網絡通訊用的小的MFC程序。發現

(1)MFC寫界面真的好麻煩呀。  用C#寫的tab 分分鍾搞定的事,用C++害得我寫了兩天.關鍵是不熟練. 還有list control 控件的圖標顯示.  真是很麻煩

         不過,由於最后的 detch() 函數執行后,就真正顯示出來了.這些具體的小細節,一般在 書上都沒有寫.

(2)用C++ 寫類的特征,基本上與C#是相似的.

說一下網絡編程的問題吧

1\一開始並不清楚 C++ 寫程序用的網絡套接字,三類的不一樣的地方.總以為我用的VS2013,用最高級別的套接字應該更容易一些,於是選用了CSOCKET 結果由於這個套接字是阻塞模式,結果被卡住了,卡住不知道如何做了.如果對方設備沒有反應,最不能死等吧,這樣不行.

於上網上搜索,發現一篇文章寫到 給 CSocket 加上超時.於時照抄照搬着做了一遍,可惜失敗了.  怎么查也查不出原因.  按原文章一字一句的比較,也沒有找出原因來.失敗換思路

2\想到低一點的 CAsyncSocket 是異步操作的.這樣總可以了吧不會阻塞了吧.但是回調函數使得處理起來也不方便.在什么時候做處理,就需要消息做處理.但是也很麻煩.

3\於是,找出書來,大部分書上對於網絡部分只是介紹了一個最基本的 Socket ,看起來也挺簡單的. 就先試一下這個最基本的吧.

沒想到 30分鍾后,網絡程序測試成功.  而且有超時接收,超時發送,等.正合我意.

原來最基本的,才是最好的.

總結一下:

     SOCKET的操作方法

 

以下是一個網絡客戶端的例子:

// client.cpp  
  
#include <iostream>  
#include <cstdio>  
#include <Winsock2.h>  
  
using namespace std;  
  
int main()  
{  
// 加載socket動態鏈接庫(dll)  
    WORD wVersionRequested;  
    WSADATA wsaData;    // 這結構是用於接收Wjndows Socket的結構信息的  
    int err;  
       
    wVersionRequested = MAKEWORD( 1, 1 );   // 請求1.1版本的WinSock庫  
       
    err = WSAStartup( wVersionRequested, &wsaData );  
    if ( err != 0 ) {  
        return -1;          // 返回值為零的時候是表示成功申請WSAStartup  
    }  
       
    if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {  
        // 檢查這個低字節是不是1,高字節是不是1以確定是否我們所請求的1.1版本  
        // 否則的話,調用WSACleanup()清除信息,結束函數  
        WSACleanup( );  
        return -1;   
    }  
      
// 創建socket操作,建立流式套接字,返回套接字號sockClient  
    // SOCKET socket(int af, int type, int protocol);  
    // 第一個參數,指定地址簇(TCP/IP只能是AF_INET,也可寫成PF_INET)  
    // 第二個,選擇套接字的類型(流式套接字),第三個,特定地址家族相關協議(0為自動)  
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);  
  
// 將套接字sockClient與遠程主機相連  
    // int connect( SOCKET s,  const struct sockaddr* name,  int namelen);  
    // 第一個參數:需要進行連接操作的套接字  
    // 第二個參數:設定所需要連接的地址信息  
    // 第三個參數:地址的長度  
    SOCKADDR_IN addrSrv;  
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");      // 本地回路地址是127.0.0.1;   
    addrSrv.sin_family = AF_INET;  
    addrSrv.sin_port = htons(6000);  
    connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));  
  
    char recvBuf[100];  
    recv(sockClient, recvBuf, 100, 0);  
    printf("%s\n", recvBuf);  
  
    send(sockClient, "Attention: A Client has enter...\n", strlen("Attention: A Client has enter...\n")+1, 0);  
  
    printf("我們可以聊五句話");  
    int n = 5;  
    do{  
        printf("\n還剩%d次:", n);  
        char talk[100];  
        printf("\nPlease enter what you want to say next(\"quit\"to exit):");  
        gets(talk);  
        send(sockClient, talk, strlen(talk)+1, 0);          // 發送信息  
  
        char recvBuf[100];  
        recv(sockClient, recvBuf, 100, 0);  
        printf("%s Says: %s\n", "Server", recvBuf);     // 接收信息  
    }while(--n);  
  
    printf("End linking...\n");  
    closesocket(sockClient);  
    WSACleanup();   // 終止對套接字庫的使用  
  
    printf("\n");  
    system("pause");  
    return 0;  
}

 

 

 

關於超時的處理方法

在send(),recv()過程中有時由於網絡狀況等原因,收發不能預期進行,而設置收發超時控制:

在Linux下需要注意的是時間的控制結構是struct timeval而並不是某一整型數,

windows下是這樣寫的:
int nNetTimeout=1000;//1秒,
//設置發送超時
setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//設置接收超時
setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

這樣做在Linux環境下是不會產生效果的,須如下定義:

struct timeval timeout = {3,0};
//設置發送超時
setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));

//設置接收超時
setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));

有兩點注意就是:

1)recv ()的第四個參數需為MSG_WAITALL(設置MSG_DONTWAIT可以不用阻塞在建立連接后在等等接收數據),在阻塞模式下不等到指定數目的數據不會返回,除非超時時間到。還要注意的是只要設置了接收超時,在沒有MSG_WAITALL時也是有效的。說到底超時就是不讓你的程序老在那兒等,到一定時間進行一次返回而已。

2)即使等待超時時間值未到,但對方已經關閉了socket, 則此時recv()會立即返回,並收到多少數據返回多少數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM