1. 程式人生 > >windows網絡編程-C語言實現簡單的UDP協議聊天

windows網絡編程-C語言實現簡單的UDP協議聊天

無連接 ipv4地址 ast 電腦 tdi data rcp proto 生生

  與TCP協議下編寫服務端程序代碼類似,但因為是無連接的形式,所以不需要監聽。

  這次,我用了一點不同的想法:我建立一個服務端,用了兩個端口和兩個套接字,把服務端作為一個數據轉發的中轉站,使得客戶機之間進行UDP協議下的通信。

  服務端代碼:

/**
 *  UDP/IP 服務器端 Server.c
 */
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define true 1
#define false 0

#define BUFFSIZE 1024

int main(int argc, char**argv)
{
    int             Ret;
    WSADATA         wsaData;
    SOCKET          Socket_1;
    SOCKET          Socket_2;
    SOCKADDR_IN     ClientAddr_1;
    int             ClientAddr_1_Len = sizeof(ClientAddr_1);
    SOCKADDR_IN     ClientAddr_2;
    int             ClientAddr_2_Len = sizeof(ClientAddr_2);
    unsigned short  Port_1 = 5150;
    unsigned short  Port_2 = 8888;
    char            sendData[BUFFSIZE];
    char            recvData[BUFFSIZE];

    if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
    {
        printf("WSASTARTUP_ERROR: %d\n", Ret);
        exit(1);
    }

    if((Socket_1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
        printf("Socket_1_ERROR\n");
        exit(1);
    }
    //將端口變量從主機字節順序轉換位網絡字節順序
    ClientAddr_1.sin_family = AF_INET;
    ClientAddr_1.sin_port = htons(Port_1);
    ClientAddr_1.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    //使用bind將這個地址信息和套接字綁定起來
    if(bind(Socket_1, (SOCKADDR *)&ClientAddr_1, ClientAddr_1_Len) == SOCKET_ERROR)
    {
        printf("BIND_SOCKET_1_ERROR: %d\n", SOCKET_ERROR);
        exit(1);
    }

    if((Socket_2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
        printf("Socket_2_ERROR\n");
        exit(1);
    }
    //將端口變量從主機字節順序轉換位網絡字節順序
    ClientAddr_2.sin_family = AF_INET;
    ClientAddr_2.sin_port = htons(Port_2);
    ClientAddr_2.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    //使用bind將這個地址信息和套接字綁定起來
    if(bind(Socket_2, (SOCKADDR *)&ClientAddr_2, ClientAddr_2_Len) == SOCKET_ERROR)
    {
        printf("BIND_SOCKET_2_ERROR: %d\n", SOCKET_ERROR);
        exit(1);
    }

    printf("建立連接成功!");

    //服務器作為中轉站
    //為兩個IP之間互相轉發消息
    while(true)
    {
        //接收IP:192.168.1.2發送的數據
        recvfrom(Socket_1, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_1, &ClientAddr_1_Len);
        strcpy(sendData, recvData);
        //轉發數據給IP:192.168.1.6
        if((Ret = sendto(Socket_2, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_2, ClientAddr_2_Len)) < 0)
            printf("發送失敗!\n");

        //接收IP:192.168.1.6發送的數據
        recvfrom(Socket_2, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_2, &ClientAddr_2_Len);
        strcpy(sendData, recvData);
        //轉發數據給IP:192.168.1.2
        if((Ret = sendto(Socket_1, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr_1, ClientAddr_1_Len)) < 0)
            printf("發送失敗!\n");
    }
    closesocket(Socket_1);
    closesocket(Socket_2);

    //應用程序完成對接的處理後,調用WSACleanup
    if(WSACleanup() == SOCKET_ERROR)
    {
        printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
        exit(1);
    }

    system("pause");
    return 0;
}

  但會有個小問題,首先發送數據的客戶端的數據無法接收,而且要運行成功必須先發送一個信息,再打開第二個客戶端(步驟貌似是這樣,前段時間寫的了,忘記了...= =)

  客戶端1代碼:

/**
 *  UDP/IP 客戶端 Client.c
 */
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define true 1
#define false 0

#define BUFFSIZE 1024

int main(int argc, char**argv)
{
    int             Ret;
    WSADATA         wsaData;
    SOCKET          SendSocket;
    SOCKADDR_IN     ClientAddr;
    int             ClientAddrLen = sizeof(ClientAddr);
    unsigned short  Port = 5150;
    char            sendData[BUFFSIZE];
    char            recvData[BUFFSIZE];
    time_t          rawtime;

    if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
    {
        printf("WSASTARTUP_ERROR: %d\n", Ret);
        exit(1);
    }

    if((SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
        printf("SendSOCKET_ERROR\n");
        exit(1);
    }

    ClientAddr.sin_family = AF_INET;
    ClientAddr.sin_port = htons(Port);
    ClientAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.2");//本機IPv4地址

    printf("連接到IP:%s 端口:%d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));
    puts("-----開始聊天!-----");
    //這樣的循環聊天算法硬生生的把UDP協議弄得和前面TCP協議的聊天程序一樣了。。。
    //感覺並不太能表現UDP和TCP的區別。。。但我暫時沒有好辦法
    while(true)
    {
        //發送數據
        printf("\nC.C.:");
        scanf("%s", sendData);
        strcat(sendData, "\t____");
        time(&rawtime);
        strcat(sendData, ctime(&rawtime));
        if((Ret = sendto(SendSocket, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, ClientAddrLen)) < 0)
            printf("發送失敗!\n");

        //接收數據
        if((Ret = recvfrom(SendSocket, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, &ClientAddrLen)) >= 0)
            printf("魯魯:%s\n", recvData);
        else
            printf("接收失敗!\n");
    }
    closesocket(SendSocket);

    if(WSACleanup() == SOCKET_ERROR)
    {
        printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
        exit(1);
    }

    system("pause");
    return 0;
}

  按照思路即可編寫客戶端2的代碼,代碼也基本一樣,就是端口號不能一樣,需要對應服務端給定的另外一個端口號:

/**
 *  UDP/IP 客戶端 Client.c
 */
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define true 1
#define false 0

#define BUFFSIZE 1024

int main(int argc, char**argv)
{
    int             Ret;
    WSADATA         wsaData;
    SOCKET          SendSocket;
    SOCKADDR_IN     ClientAddr;
    int             ClientAddrLen = sizeof(ClientAddr);
    unsigned short  Port = 8888;
    char            sendData[BUFFSIZE];
    char            recvData[BUFFSIZE];
    time_t          rawtime;

    if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
    {
        printf("WSASTARTUP_ERROR: %d\n", Ret);
        exit(1);
    }

    if((SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
        printf("SendSOCKET_ERROR\n");
        exit(1);
    }

    ClientAddr.sin_family = AF_INET;
    ClientAddr.sin_port = htons(Port);
    ClientAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.2");/** 
* 服務端程序的計算機的IPv4地址
* 顯然這整個聊天程序至少需要兩臺電腦,一臺電腦可以為服務端和客戶端,另外再一臺電腦為客戶端。或者有三臺電腦就更不容易糊塗了,一臺作為服務端,另外兩臺都是客戶端。*/

    printf("連接到IP:%s 端口:%d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));
    puts("-----開始聊天!-----");
    while(true)
    {
        //接收數據
        if((Ret = recvfrom(SendSocket, recvData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, &ClientAddrLen)) >= 0)
            printf("C.C.:%s\n", recvData);
        else
            printf("接收失敗!\n");

        //發送數據
        printf("\n魯魯:");
        scanf("%s", sendData);
        strcat(sendData, "\t____");
        time(&rawtime);
        strcat(sendData, ctime(&rawtime));
        if((Ret = sendto(SendSocket, sendData, BUFFSIZE, 0, (SOCKADDR*)&ClientAddr, ClientAddrLen)) < 0)
            printf("發送失敗!\n");

    }
    closesocket(SendSocket);

    if(WSACleanup() == SOCKET_ERROR)
    {
        printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
        exit(1);
    }

    system("pause");
    return 0;
}

windows網絡編程-C語言實現簡單的UDP協議聊天