TCPIP協議編程:基於UDP協議的局域網聊天工具的研發

任務目標

  1. 聊天器採用客戶端/服務器(C/S)模式;
  2. 客戶端利用UDP與服務器相連,客戶端與客戶端之間經過UDP相互通訊;
  3. 服務器端具備服務器端口設置維護客戶端我的信息,記錄客戶端狀態,分配帳號等;
  4. 客戶端具備服務器地址及端口設置,用戶註冊,用戶登錄,添加好友和刪除好友,查看好友信息,給好友發送消息等功能;
  5. 服務器與客戶端間、客戶端之間的交互採用控制檯方式或GUI窗口方式都可;

完成狀況

採用了客戶器/服務器模式,實現了基於UDP客戶端之間的相互通訊,其優勢有:在服務器端具備維護客戶端我的信息,記錄客戶端狀態,分配帳號,服務器地址和端口的配置等。客戶端上也實現了,地址及端口的設置用戶註冊和用戶登陸,添加好友及刪除好友,查看好友是否在線,給好友發送消息等。可是不足的是,咱們沒有設計GUI窗口界面沒有更加美觀,而是用簡潔的代碼直接在運行中顯示菜單欄;沒有作出咱們理想中的黑名單,咱們本意上是打算實現黑名單功能,設置成黑名單的人不能發消息給我,除了黑名單的均可以發,只容許好友發,這個打算由於能力有限,並無實現;接收緩衝區有延遲,處理不及時,須要先接收完上次數據才能夠繼續接受數據;羣聊功能沒有實現,只能私聊單個客戶端對客戶端的通訊;發送和接受不能以多線程的方式同時進行,消息須要咱們主動去接受。前端

運行效果圖

服務器菜單:
數據庫

服務器端口配置:
windows

查看當前全部帳戶:數組

開啓服務器:
服務器

客戶端菜單:
網絡

修改IP和端口號:
多線程

註冊帳號:
socket

登陸:
ui

查看好友列表(空):
spa

ID1003添加好友:

查看1003和1004好友:

狀態值爲1爲在線,0爲離線:

1004發送信息至1003:

1003接受信息:

刪除好友:

理論基礎

UDP是OSI 參考模型中一種無鏈接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務, UDP在IP報文的協議號是17。UDP協議的主要做用是將網絡數據流量壓縮成數據包的形式。一個典型的數據包就是一個二進制數據的傳輸單位。每個數據包的前8個字節用來包含報頭信息,剩餘字節則用來包含具體的傳輸數據。
UDP報文沒有可靠性保證、順序保證和流量控制字段等,可靠性較差。可是正由於UDP協議的控制選項較少,在數據傳輸過程當中延遲小、數據傳輸效率高,適合對可靠性要求不高的應用程序,或者能夠保障可靠性的應用程序,如DNS、TFTP、SNMP等。
客戶端/服務器(C/S)模式結構的基本原則是將計算機應用任務分解成多個子任務,由多臺計算機分工完成,即採用「功能分佈」原則。客戶端完成數據處理,數據表示以及用戶接口功能;服務器端完成DBMS(數據庫管理系統)的核心功能。這種客戶請求服務、服務器提供服務的處理方式是一種新型的計算機應用模式。

工做原理

採用客戶端/服務器(C/S)模式;客戶端利用UDP與服務器鏈接,客戶端與客戶端之間經過UDP互相通信;服務器端具備服務器端口設置,維護客戶端我的信息,記錄客戶端狀態,分配帳號等功能。客戶端具備服務器地址及端口設置,用戶註冊,用戶登錄,添加好友和刪除好友,查看好友信息,給好友發送消息等功能;服務器與客戶端間、客戶端之間的交互採用控制檯方式方式。主要是用規定好的格式發送字符信息。

核心代碼

服務器端:

data.h
#include <Winsock2.h>

struct Friends
{
    int id;
    int ava; //是否有效 1 有效 ,0 無效
};

struct User
{
    int id;
    char name[15];
    int online; //是否在線 1 在線 ,0 離線
    char passwd[15];
    sockaddr_in addr;
    Friends friends[50];
};

server.h
#include "data.h"
#include <string>
using namespace std;
//#include "net.cpp"

//net.cpp
void serverStart(User user[], int po);

//user.cpp
void saveFile(User user[]);
void readFile(User user[]);
int login(User user[], char str[]);
int reg(User user[], char str[]);
string watch(User user[], char str[]);
int delF(User user[], char str[]);
int addF(User user[], char str[]);

user.cpp
#include "data.h"
#include <string.h>
#include <stdio.h>
#include <string>
using namespace std;
//#include <stdio.h>

//從文件讀取
void readFile(User user[])
{
}

//保存到文件
void saveFile(User user[])
{
}

//用戶登陸判斷
int login(User user[], char str[])
{
    int id;
    char passwd[15];
    //char passwd1[15];
    sscanf(str, "%d %[^'\0']", &id, passwd); //接收用戶發送的id 和 密碼
    //sprintf(passwd,"%s'\0'",passwd1);
    printf("登陸判斷:%d %s \n", id, passwd);

    //int size = sizeof(user) / sizeof(user[0]);

    for (int i = 0; user[i].id != -1; i++)
    {
        printf("當前 id : %d %s \n", user[i].id, user[i].passwd);
        if (user[i].id == id)
        { //id匹配判斷
            printf("id == id : %d %s \n", user[i].id, user[i].passwd);
            if (strcmp(user[i].passwd, passwd) == 0)
            { //密碼匹配判斷
                user[i].online = 1;
                return i;
            }
            else
                return -1;
            //return i;
        }
    }
    return -1;
}

//用戶註冊
int reg(User user[], char str[])
{
    //User p;
    //int id = 1000;
    char name[15];
    char passwd[15];
    sscanf(str, "%s %s", name, passwd); //讀取用戶名 密碼
    for (int i = 0; user[i].id != -1; i++) //找到user表最後一個(id=-1)
    {
        /*  if(strcmp(User[i].id, id) == 0)
        {
            id++;
        }
        else break;*/
    }

    if (user[i].id == -1)
    { //新用戶數據保存到user裏
        user[i].id = user[i - 1].id + 1;
        user[i].online = 0;
        //user[i].name=name;
        //user[i].passwd=passwd;
        strcpy(user[i].name, name);
        strcpy(user[i].passwd, passwd);
        user[i].friends[0].id = -1;
        user[i + 1].id = -1;
        user[i + 1].friends[0].id = -1;
        return i;
    }
    return -1;
}

//查看用戶好友列表
string watch(User user[], char str[])
{
    int id;
    //char buf[1024];
    string st = "好友列表: \n-------\n";
    sscanf(str, "%d", &id);
    printf("\n --%d \n", id);
    for (int i = 0; user[i].id != -1; i++)
    { //先找到用戶再user的下標,再經過friends數組反向找好友的user下標,便可獲取信息
        if (user[i].id == id)
        {
            printf("匹配到 %d \n", user[i].id);
            for (int j = 0; user[i].friends[j].id != -1; j++)
            {
                printf("user[i].friends[j].id = %d \n", user[i].friends[j].id);
                if (user[i].friends[j].ava != 0)
                {
                    int k = 0;
                    for (k = 0; user[k].id != -1; k++)
                    {
                        if (user[k].id == user[i].friends[j].id)
                            break;
                    }
                    char temp[100];
                    sprintf(temp, "ID : %d 用戶名: %s 狀態: %d \n", user[k].id, user[k].name, user[k].online);
                    //itoa
                    //st = st + "ID : " + user[k].id + " 用戶名: " + user[k].name + " 狀態: " + user[k].online + "\n";
                    st = st + temp;
                }
            }
            //st = st + '\0';
            //char* buf = (char*)st.data();
            //printf("%s",buf);
            //return buf;
            return st;
        }
    }
    return "error";
}

//刪除好友
int delF(User user[], char str[])
{
    int Uid, Fid, uid, fid;
    sscanf(str, "%d %d", &uid, &fid);

    printf("delF: %d %d \n", uid, fid);

    for (Uid = 0; user[Uid].id != -1; Uid++)
    {
        if (user[Uid].id == uid)
        {
            break;
        }
    }
    //Uid--;
    //if(user[Uid].id==-1) return -1;

    for (Fid = 0; user[Fid].id != -1; Fid++)
    {
        if (user[Fid].id == fid)
        {
            break;
        }
    }
    //Fid--;
    //if(user[Fid].id==-1) return -1;

    //雙向刪除好友
    int i = 0;
    for (i = 0; user[Uid].friends[i].id != -1; i++)
    {
        if (user[Uid].friends[i].id == fid)
        {
            user[Uid].friends[i].ava = 0;
            break;
        }
    }

    for (i = 0; user[Fid].friends[i].id != -1; i++)
    {
        if (user[Fid].friends[i].id == uid)
        {
            user[Fid].friends[i].ava = 0;
            break;
        }
    }

    return 1;
}

//添加好友
int addF(User user[], char str[])
{
    int Uid, Fid, uid, fid;
    sscanf(str, "%d %d", &uid, &fid);

    printf("addF: %d %d \n", uid, fid);

    for (Uid = 0; user[Uid].id != -1; Uid++)
    {
        if (user[Uid].id == uid)
        {
            break;
        }
    }
    //Uid--;
    //if(user[Uid].id==-1) return -1;

    for (Fid = 0; user[Fid].id != -1; Fid++)
    {
        if (user[Fid].id == fid)
        {
            break;
        }
    }
    //Fid--;
    //if(user[Fid].id==-1) return -1;

    printf("Uid %d Fid %d \n", Uid, Fid);

    //雙向添加好友
    printf("* 0 *\n");
    int i = 0;
    for (i = 0; user[Uid].friends[i].id != -1; i++)
    {
        if (user[Uid].friends[i].id == uid)
            return -1;
    }
    printf("* 1 *\n");
    if (user[Uid].friends[i].id == -1)
    {
        user[Uid].friends[i].id = fid;
        user[Uid].friends[i].ava = 1;
        user[Uid].friends[i + 1].id = -1;
        user[Uid].friends[i + 1].ava = 0;
    }
    printf("* 2 *\n");
    for (i = 0; user[Fid].friends[i].id != -1; i++)
    {
        if (user[Fid].friends[i].id == fid)
            return -1;
    }
    printf("* 3 *\n");
    if (user[Fid].friends[i].id == -1)
    {
        user[Fid].friends[i].id = uid;
        user[Fid].friends[i].ava = 1;
        user[Fid].friends[i + 1].id = -1;
        user[Fid].friends[i + 1].ava = 0;
    }
    printf("* 4 *\n");
    return 1;
}

net.cpp
#include <Winsock2.h>
#include <stdio.h>

#include "server.h"
//#include "data.h"

void serverStart(User user[], int po)
{
    //加載套接字庫
    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;
    }

    printf("server is operating!\n\n");
    //建立用於監聽的UDP套接字
    SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);

    SOCKADDR_IN addrSrv; //定義sockSrv發送和接收數據包的地址
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrSrv.sin_family = AF_INET;
    //addrSrv.sin_port = htons(6000);
    addrSrv.sin_port = htons(po);

    //綁定套接字, 綁定到端口
    bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
    //將套接字設爲監聽模式, 準備接收客戶請求

    SOCKADDR_IN addrClient; //用來接收客戶端的地址信息
    int len = sizeof(SOCKADDR);
    //char recvBuf[1024]; //收
    //char sendBuf[1024]; //發
    //char tempBuf[1024]; //存儲中間信息數據

    while (1)
    {
        char *recvBuf = new char[1024]; //接收數據
        char *sendBuf = new char[1024]; //發送數據
        char *tempBuf = new char[1024]; //臨時數據
        //等待並數據
        recvfrom(sockSrv, recvBuf, 1024, 0, (SOCKADDR *)&addrClient, &len);

        //sprintf(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf);
        //printf("info -> %s \n",tempBuf);

        char type;
        //char msg[1024];
        char *msg = new char[1024];

        //將收到的信息進行拆分判斷
        sscanf(recvBuf, "%c %[^\n]", &type, msg);
        int res = 0;

        printf("消息類型: %c \n", type);
        //printf(" Msg: %s \n",msg);

        switch (type)
        {
        case 'L': //登陸
            res = login(user, msg);
            if (res != -1)
            {
                user[res].addr = addrClient; //保存
                user[res].online = 1;
                sendto(sockSrv, "登陸成功", strlen("登陸成功") + 1, 0, (SOCKADDR *)&addrClient, len);
            }
            else
            {
                sendto(sockSrv, "q", strlen("q") + 1, 0, (SOCKADDR *)&addrClient, len);
            }
            break;
        case 'S': //發送
        {
            int id, i, f = 0;
            char sendMsg[1024];
            sscanf(msg, "%d %s", &id, sendMsg); //拆分信息
            printf("id: %d", id);
            printf("msg: %s", sendMsg);
            for (i = 0; user[i].id != -1; i++)
            {
                if (user[i].id == id)
                { //匹配發送方id
                    if (user[i].online == 1)
                    { //對方在線
                        char newsend[1024];
                        sprintf(newsend, "%s -> %s \n", user[i].name, sendMsg);
                        sendto(sockSrv, newsend, strlen(newsend) + 1, 0, (SOCKADDR *)&user[i].addr, len);
                        sendto(sockSrv, "發送成功", strlen("發送成功") + 1, 0, (SOCKADDR *)&addrClient, len); //往發送方返回成功信息
                        f = 1;
                    }
                    else
                        sendto(sockSrv, "對方不在線", strlen("對方不在線") + 1, 0, (SOCKADDR *)&addrClient, len); //不在線
                }
            }
            if (f == 0)
                sendto(sockSrv, "對方不存在", strlen("對方不存在") + 1, 0, (SOCKADDR *)&addrClient, len); //不存在
            break;
        }
        case 'R': //註冊
        {
            res = reg(user, msg);
            char buf[1024];
            sprintf(buf, "你的ID : %d , 你的名字 : %s , 你的密碼 : %s\n", user[res].id, user[res].name, user[res].passwd);
            /*if(res!=-1){
                    user[res].addr = addrClient;
                    user[res].online = 1;
                } else {
                    sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len);
                }*/
            sendto(sockSrv, buf, strlen(buf) + 1, 0, (SOCKADDR *)&addrClient, len); //返回註冊信息
            break;
        }
        case 'F': //好友功能
        {
            char type2, more[50];
            sscanf(msg, "%c %[^\n]", &type2, more);
            printf("-- %c %s --\n", type2, more);
            switch (type2)
            {
            case 'A': //添加好友
                addF(user, more);
                sendto(sockSrv, "add ok", strlen("add ok") + 1, 0, (SOCKADDR *)&addrClient, len);
                break;
            case 'D': //刪除好友
                delF(user, more);
                sendto(sockSrv, "del ok", strlen("del ok") + 1, 0, (SOCKADDR *)&addrClient, len);
                break;
            case 'W': //查看好友
                //char bufW[512];
                string st = watch(user, more);
                char *bufW = (char *)st.data();
                //char* bufW = watch(user , more );
                printf("%s", bufW);
                sendto(sockSrv, bufW, strlen(bufW) + 1, 0, (SOCKADDR *)&addrClient, len);
                break;
            }
        }
        break;
        case 'Q': //退出
        {
            int my = -1, i = 0;
            sscanf(msg, "%d", &my);
            for (i = 0; user[i].id != -1; i++)
            {
                if (user[i].id == my)
                {
                    user[i].online = 0; //下線
                }
            }
            sendto(sockSrv, "退出成功", strlen("退出成功") + 1, 0, (SOCKADDR *)&addrClient, len);
            break;
        }
        default: //不是格式輸入
            sendto(sockSrv, "請按格式輸入", strlen("請按格式輸入") + 1, 0, (SOCKADDR *)&addrClient, len);
            break;
        }

        /*      if('q' == recvBuf[0])
        {
            sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len);
            printf("Chat end!\n");
            break;
        }*/

        //sprintf_s(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf);
        /*      sprintf(tempBuf,"%s say : %s",inet_ntoa(addrClient.sin_addr),recvBuf);
        printf("%s\n",tempBuf);*/

        //發送數據
        /*      printf("Please input data: \n");
        gets(sendBuf);
        sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);*/
    }
    closesocket(sockSrv);
    WSACleanup();
}


server.cpp
#include "server.h"
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <conio.h>
using namespace std;
//#include "data.h"

int po = 8089;

void PortConfig()
{
    system("cls");
    printf("當前端口號 : %d ,請輸入新端口號:", po);
    scanf("%d", &po);
    printf("新的端口號爲 : %d\n回車返回", po);
    getchar();
    getchar();
} //端口配置

void Mainte(User user[])
{
    system("cls");
    printf("1.查看信息 2.修改信息\n請輸入:");
    char ch;
    ch = getch();
    system("cls");
    if ('1' == ch)
        for (int i = 0; user[i].id != -1; i++)
        {
            printf("第%d條記錄->ID:%d 用戶名:%s 密碼:%s \n", i, user[i].id, user[i].name, user[i].passwd);
        }
    else
    {
        int id, i;
        char name[15];
        char passwd[15];
        printf("請輸入id:");
        scanf("%d", &id);
        printf("請輸入名字:");
        scanf("%s", name);
        printf("請輸入密碼:");
        scanf("%s", passwd);

        printf("你的輸入: %d %s %s\n", id, name, passwd);
        for (i = 0; user[i].id != -1; i++)
        {
            if (user[i].id == id)
            {
                system("cls");
                printf("匹配到 %d", user[i].id);
                //sprintf(user[i].name,"%s",name);
                //sprintf(user[i].name,"%s",passwd);
                //printf(" %s ",user[i].name);
                //printf("原記錄->ID:%d 用戶名:%s 密碼:%s \n",i,user[i].id,user[i].name,user[i].passwd);
                strcpy(user[i].name, name);
                strcpy(user[i].passwd, passwd);
                //printf(" %s ",user[i].name);
                printf("更改爲功->ID:%d 用戶名:%s 密碼:%s \n", user[i].id, user[i].name, user[i].passwd);
                break;
            }
        }
    }
    getchar();
    getchar();
} //維護客戶端我的信息

void Start(User user[])
{
    serverStart(user, po);
} //開啓服務器

void Distr(User user[])
{
    system("cls");
    char buf[50];
    int i;
    printf("請輸入名字 密碼:");
    scanf("%[^\n]", buf);
    i = reg(user, buf);
    if (i != -1)
    {
        printf("新註冊賬號 -> ID:%d 用戶名:%s 密碼:%s \n", user[i].id, user[i].name, user[i].passwd);
    }
    else
        printf("建立失敗!回車返回");
    getchar();
    getchar();
} //分配帳號

void MenuShow()
{
    system("cls");
    printf("***************************************************************************************************************\n");
    printf(" |>> Server <<| \n\n");
    printf(" |>> 1.服務器 端口 配置 <<| \n\n");
    printf(" |>> 2.維護客戶端我的信息 <<| \n\n");
    printf(" |>> 3.開啓 服務器 <<| \n\n");
    printf(" |>> 4.分 配 帳 號 <<| \n\n");
    printf(" |>> 5.退 出 <<| \n\n");
    printf("***************************************************************************************************************\n");
}

void SMenu(User user[])
{
    int f = 1;
    while (f)
    {
        MenuShow();
        printf("選擇以上編號:");
        char i;
        i = getch();
        switch (i)
        {
        case '1':
        {
            PortConfig();
            break;
        }

        case '2':
        {
            Mainte(user);
            break;
        }

        case '3':
        {
            system("cls");
            Start(user);
            break;
        }

        case '4':
        {
            Distr(user);
            break;
        }

        case '5':
            f = 0;
            break;

        default:
        {
            printf("輸入錯誤!");
            break;
        }
        }
    }
} //服務器端菜單選擇

void main()
{
    User user[50]; //初始化 user 表

    //user[0]=new User;
    user[0].id = 1001;
    user[0].online = 0;
    strcpy(user[0].name, "b");
    strcpy(user[0].passwd, "1001");
    user[0].friends[0].id = -1;
    //user[0].name = "b";
    //user[0].passwd = "1001";
    //printf("%s %s",user[0].name,user[0].passwd);
    //user[1]=new User;
    user[1].id = 1002;
    user[1].online = 0;
    strcpy(user[1].name, "c");
    strcpy(user[1].passwd, "1002");
    user[1].friends[0].id = -1;
    //user[1].name = "b";
    //user[1].passwd = "1001";

    //user[2]=new User;
    user[2].id = -1;
    user[2].online = 0;
    user[2].friends[0].id = -1;

    //serverStart(user,8089);

    SMenu(user);
}

客戶端:

client.h
void sendAll(char ipaddr[],int port);
int sendM(SOCKET sockSrv,char ipaddr[],int port,char sendBuf[],sockaddr_in addrSrv);

client.cpp
#include <Winsock2.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>

#include "client.h"
// 必須的頭文件

//程序入口
int main()
{
    char ipaddr[25] = "127.0.0.1";
    int port = 8089;

    /*  WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    int id;
    wVersionRequested = MAKEWORD(1,1);
    err = WSAStartup(wVersionRequested, &wsaData);
    if(err != 0)
    {
        return 5;
    }
    if(LOBYTE(wsaData.wVersion) != 1 || 
        HIBYTE(wsaData.wVersion) != 1) 
    {
        WSACleanup();
        return 5;
    }
    printf("Client is operating!\n\n");
    SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);

    sockaddr_in addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(port);*/

    int len = sizeof(SOCKADDR);

    while (1)
    {
        system("cls");
        printf("***************************************************************************************************************\n\n");
        printf(" |>> Client <<| \n\n");
        printf(" |>> 1.服務器地址和端口配置 <<| \n\n");
        printf(" |>> 2.賬號註冊 <<| \n\n");
        printf(" |>> 3.用戶登陸 <<| \n\n");
        printf(" |>> 4.退出 <<| \n\n");
        printf("***************************************************************************************************************\n\n");
        printf("請輸入:");
        char ch;
        ch = getch();
        switch (ch)
        {
        case '1': //修改配置
        {
            char ipA[15];
            int po;
            system("cls");
            printf("請輸入IP:");
            scanf("%s", ipA);
            printf("請輸入端口:");
            scanf("%d", &po);
            strcpy(ipaddr, ipA);
            port = po;
            printf("修改爲功");
            getchar();
            getchar();
        }
        break;
        case '2': //添加用戶
        {

            WORD wVersionRequested;
            WSADATA wsaData;
            int err;
            int id;

            wVersionRequested = MAKEWORD(1, 1);

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

            if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本
                HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本
            {
                WSACleanup();
                return 5;
            }

            printf("Client is operating!\n\n");
            //建立用於監聽的套接字
            SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);

            sockaddr_in addrSrv;
            addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr);
            addrSrv.sin_family = AF_INET;
            addrSrv.sin_port = htons(port);

            int len = sizeof(SOCKADDR);

            system("cls");
            printf("請輸入用戶名 密碼:");
            char buf[100], msg[100];
            scanf("%[^\n]", buf);
            sprintf(msg, "R %s", buf);
            sendM(sockSrv, ipaddr, port, msg, addrSrv);
            getchar();
            getchar();
            break;
        }
        case '3': //登陸
            system("cls");
            sendAll(ipaddr, port);
            break;
        case '4':
        default:
            return 0;
        }
    }
}


send.cpp
#include <Winsock2.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
// 必須的頭文件

/*
struct Args{
int s; void *buf; int len; unsigned int flags; struct sockaddr *from; int *fromlen;
};

DWORD WINAPI ThreadFunc(LPVOID lp);
*/

int sendM(SOCKET sockSrv, char ipaddr[], int port, char sendBuf[], sockaddr_in addrSrv)
{
    //加載套接字庫
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(1, 1);

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

    if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本
        HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本
    {
        WSACleanup();
        return -1;
    }

    printf("Client is operating!\n\n");
    //建立用於監聽的套接字
    //SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);

    /*sockaddr_in addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(port);*/

    int len = sizeof(SOCKADDR);

    char *recvBuf = new char[1024];
    //char *sendBuf=new char[1024];
    char *tempBuf = new char[1024];

    //scanf("%[^\n]",sendBuf);
    //printf("%s",sendBuf);

    if ('!' != sendBuf[0])
        sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);
    //等待並數據
    int res = 0;
    res = recvfrom(sockSrv, recvBuf, 1024, 0, (SOCKADDR *)&addrSrv, &len);

    if (res == -1)
        printf("暫時無數據!\n");
    else
        printf("%s \n", recvBuf);

    if ('q' == recvBuf[0])
    {
        return 1;
        //sendto(sockSrv,"Q",strlen("Q")+1,0,(SOCKADDR*)&addrSrv,len);
        //printf("Chat end!\n");
    }

    //sprintf(tempBuf,"%s say : %s",inet_ntoa(addrSrv.sin_addr),recvBuf);
    //scanf(recvBuf,"%[^'\0']",tempBuf);
    //sprintf(tempBuf,"temp: \n %[^'\0']",recvBuf);
    //printf("temp : \n%s \n\n",tempBuf);

    //發送數據

    //closesocket(sockSrv);
    WSACleanup();

    return 0;
}


sendAll.cpp
#include <Winsock2.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>

#include "client.h"
// 必須的頭文件

/*
struct Args{
int s; void *buf; int len; unsigned int flags; struct sockaddr *from; int *fromlen;
};

DWORD WINAPI ThreadFunc(LPVOID lp);
*/

void sendAll(char ipaddr[], int port)
{
    //加載套接字庫
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    int id;

    wVersionRequested = MAKEWORD(1, 1);

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

    if (LOBYTE(wsaData.wVersion) != 1 || //低字節爲主版本
        HIBYTE(wsaData.wVersion) != 1) //高字節爲副版本
    {
        WSACleanup();
        return;
    }

    printf("Client is operating!\n\n");
    //建立用於監聽的套接字
    SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr(ipaddr);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(port);

    int len = sizeof(SOCKADDR);

    int f = 1;
    while (f)
    { //登陸
        char buf[1024], msg[1024];
        printf("請輸入ID:");
        scanf("%d", &id);
        printf("請輸入密碼:");
        //getch();
        scanf("%s", buf);
        sprintf(msg, "L %d %s", id, buf);
        f = sendM(sockSrv, ipaddr, port, msg, addrSrv); //向服務器發送登陸信息
        if (f)
        {
            printf("登陸失敗!回車返回");
            getchar();
            getchar();
            return;
        }
        getchar();
        getchar();
    }
    f = 1;
    int op = 0;
    while (f)
    {
        char *recvBuf = new char[1024];
        char *sendBuf = new char[1024];
        char *tempBuf = new char[1024];
        char ch;
        //printf("Please input data: \n");
        printf("1.查看好友 2.發送信息 3.接收信息 4.添加好友 5.刪除好友 6.退出: \n");
        //gets(sendBuf);
        ch = getch();
        char in[1024];
        switch (ch)
        {
        case '1': //查看好友
            sprintf(sendBuf, "F W %d", id);
            sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
            break;
        case '2': //發送信息
            printf("請輸入:對方id 信息\n");
            scanf("%[^\n]", in);
            sprintf(sendBuf, "S %s", in);
            sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
            break;
        case '3': //接收信息
            sprintf(sendBuf, "!");
            sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
            break;
        case '4': //添加好友
        {
            int dstid;
            printf("請輸入:對方id\n");
            scanf("%d", &dstid);
            sprintf(sendBuf, "F A %d %d", id, dstid);
            sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
            break;
        }
        case '5': //刪除好友
        {
            int dstid;
            printf("請輸入:對方id\n");
            scanf("%d", &dstid);
            sprintf(sendBuf, "F D %d %d", id, dstid);
            sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
            break;
        }
        default:
            f = 0;
            sprintf(sendBuf, "Q %d", id);
            sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
            break;
        }
        continue;

        //scanf("%[^\n]",sendBuf);
        //printf("%s",sendBuf);

        if ('!' != sendBuf[0])
            sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);
        //等待並數據

        if ('Q' == sendBuf[0])
        {
            sendto(sockSrv, "Q", strlen("Q") + 1, 0, (SOCKADDR *)&addrSrv, len);
            printf("Chat end!\n");
            break;
        }

        recvfrom(sockSrv, recvBuf, 1024, 0, (SOCKADDR *)&addrSrv, &len);

        if ('q' == recvBuf[0])
        {
            sendto(sockSrv, "Q", strlen("Q") + 1, 0, (SOCKADDR *)&addrSrv, len);
            printf("Chat end!\n");
            break;
            //printf("Chat end!\n");
        }

        printf("%s \n", recvBuf);

        //發送數據
    }
    closesocket(sockSrv);
    WSACleanup();
}
相關文章
相關標籤/搜索