windows下的socket網絡編程


windows下的socket網絡編程

已經很久沒有在windows下編程了,這次因為需要做一個跨平台的網絡程序,就先寫了個簡單的winSocket網路通信的例子,以便以后用到的時候有個參考。

windows下使用winsock編程與linux/unix的區別在於windows下需要先有一個初始化的操作,結束的時候需要一個清理的操作。還有windows下編譯的時候需要連接ws32_lib庫。

大致過程如下

  • 1、初始化

    /*加載Winsock DLL*/
    WSADATA wsd;
    if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
    printf("Winsock 初始化失敗!\n");
    return 1;
    }

  • 2、socket相關函數調用

    socket(...)
    bind(...)
    listen(...)
    connect(...)
    accept(...)
    send/sendto
    recv/recvfrom

  • 3、清理
    WSACleanup();

clinet.c 客戶端

客戶端的流程很簡單。

  • 1、先是使用socket函數產生一個打開的socket文件描述符。
  • 2、使用connect函數去連接服務端
  • 3、使用read/recv等讀文件函數從服務端接收數據,使用write/send等寫文件的函數向服務端發送數據

上面是典型的TCP編程流程,如果是UDP的話不需要connect去連接服務端直接使用sendto函數來發送數據,使用recvfrom接收來自服務器的數據

server.c 服務器端

服務器端的流程比客戶端稍微復雜一點

  • 1、調用socket打開一個socket句柄
  • 2、調用bind來綁定socket句柄到一個網口的某個端口
  • 3、調用listen來設置(啟用)監聽
  • 4、調用accept來等待客戶端的連接

上面是典型的TCP編程流程,如果是UDP的,那么不需要3,4這兩部,直接使用recvfrom來接收客戶端發過來的數據即可。

UDP通信的實現

我這里沒有寫TCP的,因為都是局域網內,就簡單的寫了個。
這里是在虛擬機里面測試的截圖,代碼見最后。

 

代碼如下

這是TCP的,UDP的就不貼了。

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib , "ws2_32.lib")

#define BUFSIZE 4096 /*緩沖區大小*/

int main_client(int argc , char *argv[])
{
    WSADATA wsd;
    SOCKET sClient;
    char Buffer[BUFSIZE];
    int ret;
    struct sockaddr_in server;
    unsigned short port;
    struct hostent *host = NULL;

    if (argc < 3) {
        printf("Usage:%s IP Port\n" , argv[0]);
        return -1;
    }


    /*加載Winsock DLL*/
    if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
        printf("Winsock    初始化失敗!\n");
        return 1;
    }

    /*創建Socket*/
    sClient = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
    if (sClient == INVALID_SOCKET) {
        printf("socket() 失敗: %d\n" , WSAGetLastError());
        return 1;
    }
    /*指定服務器地址*/
    server.sin_family = AF_INET;
    port = atoi(argv[2]);
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(argv[1]);

    if (server.sin_addr.s_addr == INADDR_NONE) {
        host = gethostbyname(argv[1]);    //輸入的地址可能是域名等
        if (host == NULL) {
            printf("無法解析服務端地址: %s\n" , argv[1]);
            return 1;
        }
        CopyMemory(&server.sin_addr ,
                    host->h_addr_list[0] ,
                    host->h_length);
    }
    /*與服務器建立連接*/
    if (connect(sClient , (struct sockaddr*)&server ,
                    sizeof(server)) == SOCKET_ERROR) {
        printf("connect() 失敗: %d\n" , WSAGetLastError());
        return 1;
    }

    /*發送、接收消息*/

    for (;;) {
        //從標准輸入讀取要發送的數據
        //gets_s(Buffer,BUFSIZE);
        gets(Buffer);
        //向服務器發送消息
        ret = send(sClient , Buffer , strlen(Buffer) , 0);
        if (ret == 0) {
            break;
        }
        else if (ret == SOCKET_ERROR) {
            printf("send() 失敗: %d\n" , WSAGetLastError());
            break;
        }
        printf("Send %d bytes\n" , ret);
        //接收從服務器來的消息
        ret = recv(sClient , Buffer , BUFSIZE , 0);
        if (ret == 0) {
            break;
        }
        else if (ret == SOCKET_ERROR) {
            printf("recv() 失敗: %d\n" , WSAGetLastError());
            break;
        }
        Buffer[ret] = '\0';
        printf("Recv %d bytes:\n\t%s\n" , ret , Buffer);

    }
    //用完了,關閉socket句柄(文件描述符)
    closesocket(sClient);
    WSACleanup();    //清理
    return 0;
}
查看 clinet.c 代碼
  1 #include <winsock2.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 
  5 #pragma comment(lib , "ws2_32.lib")
  6 
  7 
  8 #define DEFAULT_BUFFER 4096 /*緩沖區大小*/
  9 
 10 
 11 /*與客戶機通信的線程函數*/
 12 DWORD WINAPI ClientThread(LPVOID lpParam)
 13 {
 14     SOCKET sock = (SOCKET)lpParam;
 15     char Buffer[DEFAULT_BUFFER];
 16     int ret , nLeft , idx;
 17     while (1) {
 18         /*接收來自客戶機的消息*/
 19         ret = recv(sock , Buffer , DEFAULT_BUFFER , 0);
 20         if (ret == 0)
 21             break;
 22         else if (ret == SOCKET_ERROR) {
 23             printf("recv() 失敗: %d\n" , WSAGetLastError());
 24             break;
 25         }
 26         Buffer[ret] = '\0';
 27         printf("Recv: %s\n" , Buffer);    //打印接收到的消息
 28 
 29 
 30         nLeft = ret;
 31         idx = 0;
 32         while (nLeft > 0) {
 33             /*向客戶機發送回應消息*/
 34             ret = send(sock , &Buffer[idx] , nLeft , 0);
 35             if (ret == 0)
 36                 break;
 37             else if (ret == SOCKET_ERROR) {
 38                 printf("send() 失敗: %d\n" , WSAGetLastError());
 39                 break;
 40             }
 41             nLeft -= ret;
 42             idx += ret;
 43         }
 44     }
 45     return 0;
 46 }
 47 
 48 int main_server(int argc , char **argv)
 49 {
 50     WSADATA        wsd;
 51     HANDLE        hThread;
 52     DWORD        dwThread;
 53     SOCKET        sListen , sClient;
 54     int            AddrSize;
 55     unsigned short port;
 56     struct sockaddr_in local , client;
 57 
 58     if (argc < 2) {
 59         printf("Usage:%s Port\n" , argv[0]);
 60         return -1;
 61     }
 62 
 63     /*加載Winsock DLL*/
 64     if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
 65         printf("WinSock 初始化失敗!\n");
 66         return 1;
 67     }
 68 
 69     /*創建Socket*/
 70     sListen = socket(AF_INET , SOCK_STREAM , IPPROTO_IP);
 71     if (sListen == SOCKET_ERROR) {
 72         printf("socket() 失敗: %d\n" , WSAGetLastError());
 73         return 1;
 74     }
 75 
 76     local.sin_family = AF_INET;
 77     local.sin_addr.s_addr = htonl(INADDR_ANY);
 78     port = atoi(argv[1]);    //獲取端口值
 79     local.sin_port = htons(port);
 80 
 81     /*綁定Socket*/
 82     if (bind(sListen ,
 83         (struct sockaddr*)&local ,
 84         sizeof(local)) == SOCKET_ERROR) {
 85         printf("bind() 失敗: %d\n" , WSAGetLastError());
 86         return 1;
 87     }
 88     /*打開監聽*/
 89     listen(sListen , 8);
 90 
 91     /*在端口進行監聽,一旦有客戶機發起連接請示
 92     就建立與客戶機進行通信的線程*/
 93     while (1) {
 94         AddrSize = sizeof(client);
 95         /*監聽是否有連接請求*/
 96         sClient = accept(sListen ,
 97                          (struct sockaddr*)&client ,
 98                          &AddrSize);
 99         if (sClient == INVALID_SOCKET) {
100             printf("accept() 失敗: %d\n" , WSAGetLastError());
101             break;
102         }
103         printf("接受客戶端連接: %s:%d\n" ,
104                inet_ntoa(client.sin_addr) ,
105                ntohs(client.sin_port));
106 
107         //創建一個線程去處理
108         hThread = CreateThread(NULL , 0 , ClientThread ,
109                                (LPVOID)sClient , 0 , &dwThread);
110 
111         if (hThread == NULL) {
112             printf("CreateThread() 失敗: %d\n" , GetLastError());
113             break;
114         }
115         //處理完后關閉
116         CloseHandle(hThread);
117     }
118     closesocket(sListen);
119     WSACleanup();    //用完了要清理
120     return 0;
121 }
查看 server.c 代碼

測試代碼(main)

 1 extern int main_client(int , char**);
 2 extern int main_server(int , char**);
 3 
 4 int main(int c , char** v)
 5 {
 6     if (c == 3) {
 7         main_client(c , v);
 8     }
 9     else {
10         main_server(c , v);
11     }
12     return 0;
13 
14 }
查看 test 代碼

 


免責聲明!

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



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