1. 程式人生 > >建立一個簡單的VC++ Socket程式

建立一個簡單的VC++ Socket程式

        本文主要結合MSDN上關於WinSocket的幾篇官方文件,建立一個簡單的VC++ Socket示例程式,演示一個基本的CS模型。參考連結如下:

一、C/S —— Client和Server

        網路程式設計中,最常見的是C/S模型,它有一個(或多個)client和一個server。事實上,我們需要建立兩個不同的socket network應用程式來演示該示例(我們可以將這兩個工程放到一個solution下,具體方法是:先建立一個工程,然後修改名字,再在該solution下新增另一個工程)。這兩個應用程式——client和server有不同的行為,如下:

Server

  1. Initialize Winsock.
  2. Create a socket.
  3. Bind the socket.
  4. Listen on the socket for a client.
  5. Accept a connection from a client.
  6. Receive and send data.
  7. Disconnect.

Client

  1. Initialize Winsock.
  2. Create a socket.
  3. Connect to the server.
  4. Send and receive data.
  5. Disconnect.

二、標頭檔案和庫

        分別為client和server新建兩個普通的我win32 console程式,包含下面的標頭檔案和庫:

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

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

其中,”stdio.h“用於標準輸入輸出,如:printf()函式。需要注意的是,”winsock2.h“,官方解釋:點選開啟連結

The Winsock2.h header file internally includes core elements from the Windows.h header file, so there is not usually an #include line for the 

Windows.h header file in Winsock applications. If an #include line is needed for the Windows.h header file, this should be preceded with the #define WIN32_LEAN_AND_MEAN macro. For historical reasons, the Windows.h header defaults to including the Winsock.h header file for Windows Sockets 1.1. The declarations in the Winsock.h header file will conflict with the declarations in the Winsock2.h header file required by Windows Sockets 2.0. The WIN32_LEAN_AND_MEAN macro prevents the Winsock.hfrom being included by the Windows.h header. An example illustrating this is shown below.

注意,要帶上數字”2“。

三、client程式碼

#include <stdio.h>
#include <Winsock2.h>
#include <iostream>
#include <fstream>
using namespace std;
#pragma comment(lib,"WS2_32.lib")    // Winsocket是動態連結庫,需要載入它的庫和包含對應的標頭檔案

char recvBuf[1310721];
int _tmain(int argc, _TCHAR* argv[])
{

    WSADATA wsd;
    SOCKET sockClient;                                            //客戶端socket
    SOCKADDR_IN addrSrv;
    //char recvBuf[1310721];
    memset(recvBuf, 0, 1310721);
    if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)        // 1> 初始化Windows的socket庫(API集)
    {
        printf("start up failed!\n");
        return 0;
    }

    sockClient=socket(AF_INET,SOCK_STREAM,0);                    // 2> 建立socket
    if (INVALID_SOCKET == sockClient)
    {
        printf("create client socket error!\n");
        return 0;
    }

    addrSrv.sin_addr.S_un.S_addr=inet_addr("192.168.18.129");
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(6000);
    if (SOCKET_ERROR == connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))    //連線伺服器端
    {
        printf("connect server error!\n");
        return 0;
    }

    ofstream ofs("recv.txt");
    while (1)
    {
        printf("wait for recv data\n");
        int recvNum = recv(sockClient,recvBuf,1310721,0);                                //接收伺服器端資料
        if (recvNum == 1310721 - 1)
        {
            printf("%s\n",recvBuf);
            ofs.write("*******  ", strlen("*******  "));
            ofs.write(recvBuf, recvNum);
            ofs.write("\n\n", strlen("\n\n"));
            ofs.flush();
        }

        Sleep(1000);
    }
    ofs.flush();
    ofs.close();
    //send(sockClient,"hello world",strlen("hello world")+1,0);    //向伺服器端傳送資料
    closesocket(sockClient);                                    //關閉連線
    WSACleanup();

	return 0;
}

三、server程式碼
#include <stdio.h>
#include <Winsock2.h>
#include <iostream>
#include <fstream>
using namespace std;
#pragma comment(lib,"WS2_32.lib")

char sendBuf[1310721];
int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsd;
    SOCKET server;                                            //伺服器socket
    SOCKADDR_IN addrSrv;    
    //char sendBuf[1310721];
    //memset(&sendBuf[0], '3', 1310721);
    memset(&sendBuf[0], '9', 100000);
    memset(&sendBuf[100000], '0', 100000);
    memset(&sendBuf[200000], '4', 100000);
    memset(&sendBuf[300000], '1', 100000);
    memset(&sendBuf[400000], '8', 100000);
    memset(&sendBuf[500000], '5', 100000);
    memset(&sendBuf[600000], '2', 100000);
    memset(&sendBuf[700000], '6', 100000);
    memset(&sendBuf[800000], '3', 100000);
    memset(&sendBuf[900000], '7', 100000);
    memset(&sendBuf[1000000], '5', 310721);
    sendBuf[1310721 - 1] = '\0';
    SOCKADDR_IN addrClient;
    SOCKET client;                                            //連線的客戶端socket
    int len;
    if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)        // 1> 初始化Windows的socket庫(API集)
    {
        printf("start up failed!\n");
        return 0 ;
    }

    server = socket(AF_INET,SOCK_STREAM,0);
    if (INVALID_SOCKET == server)                    // 2> 建立socket
    {
        printf("create server socket error!\n");
        return 0;
    }

    addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);            //設定地址
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(6000);                            //設定埠號
    if (SOCKET_ERROR == bind(server,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))        // 3> 將一個socket與一個應用程式(IP + PORT_NUMBER)繫結
    {
        printf("bind error!\n");
        return 0;
    }

    if (SOCKET_ERROR == listen(server,5))                                        // 4> 設定該socket為監聽模式,設定最多連線數
    {
        printf("listen error!\n");
        return 0;
    }

    len=sizeof(SOCKADDR);

    printf("wait for accept client\n");
    client = accept(server,(SOCKADDR*)&addrClient,&len);    // 5> 監聽到請求後,接受請求,並返回對應於此處連線的套接字
    if (INVALID_SOCKET != client)
    {
        printf("Welcome %s \n", inet_ntoa(addrClient.sin_addr));
    }

    ofstream ofs("send.txt");
    while(1)
    {
        int sendNum = send(client,sendBuf,strlen(sendBuf),0);            // 6> 用返回的套接字和客戶端通訊,傳送資訊給客戶端
        if (sendNum == strlen(sendBuf))
        {
            //recv(client,recvBuf,100,0);                            // 6> 用返回的套接字和客戶端通訊,接收客戶端資料
            printf("%s\n",sendBuf);
            ofs.write("*******  ", strlen("*******  "));
            ofs.write(sendBuf, sendNum);
            ofs.write("\n\n", strlen("\n\n"));
            ofs.flush();
        }

        Sleep(1000);
    }
    ofs.flush();
    ofs.close();
    closesocket(client);                                    //關閉連線
    WSACleanup();
    

	return 0;
}