TCPIP协议编程:基于UDP协议的局域网聊天工具的研发

任务目标

  1. 聊天器采用客户端/服务器(C/S)模式;
  2. 客户端利用UDP与服务器相连,客户端与客户端之间通过UDP相互通信;
  3. 服务器端具有服务器端口设置维护客户端个人信息,记录客户端状态,分配账号等;
  4. 客户端具有服务器地址及端口设置,用户注册,用户登陆,添加好友和删除好友,查看好友信息,给好友发送消息等功能;
  5. 服务器与客户端间、客户端之间的交互采用控制台方式或GUI窗口方式均可;

完成情况

采用了客户器/服务器模式,实现了基于UDP客户端之间的相互通信,其优点有:在服务器端具有维护客户端个人信息,记录客户端状态,分配账号,服务器地址和端口的配置等。客户端上也实现了,地址及端口的设置用户注册和用户登录,添加好友及删除好友,查看好友是否在线,给好友发送消息等。但是不足的是,我们没有设计GUI窗口界面没有更加美观,而是用简洁的代码直接在运行中显示菜单栏;没有做出我们理想中的黑名单,我们本意上是打算实现黑名单功能,设置成黑名单的人不能发消息给我,除了黑名单的都可以发,只允许好友发,这个打算因为能力有限,并没有实现;接收缓冲区有延迟,处理不及时,需要先接收完上次数据才可以继续接受数据;群聊功能没有实现,只能私聊单个客户端对客户端的通信;发送和接受不能以多线程的方式同时进行,消息需要我们主动去接受。

运行效果图

服务器菜单:
TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第1张图片

服务器端口配置:
TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第2张图片

查看当前所有账户:

TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第3张图片

TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第4张图片

开启服务器:

客户端菜单:
TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第5张图片

修改IP和端口号:

注册账号:
TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第6张图片

登录:
TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第7张图片

查看好友列表(空):

ID1003添加好友:

查看1003和1004好友:

状态值为1为在线,0为离线:
TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第8张图片

1004发送信息至1003:

1003接受信息:

删除好友:

TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第9张图片

理论基础

UDP是OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务, UDP在IP报文的协议号是17。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为UDP协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如DNS、TFTP、SNMP等。
客户端/服务器(C/S)模式结构的基本原则是将计算机应用任务分解成多个子任务,由多台计算机分工完成,即采用“功能分布”原则。客户端完成数据处理,数据表示以及用户接口功能;服务器端完成DBMS(数据库管理系统)的核心功能。这种客户请求服务、服务器提供服务的处理方式是一种新型的计算机应用模式。

工作原理

采用客户端/服务器(C/S)模式;客户端利用UDP与服务器连接,客户端与客户端之间通过UDP互相通讯;服务器端具有服务器端口设置,维护客户端个人信息,记录客户端状态,分配账号等功能。客户端具有服务器地址及端口设置,用户注册,用户登陆,添加好友和删除好友,查看好友信息,给好友发送消息等功能;服务器与客户端间、客户端之间的交互采用控制台方式方式。主要是用规定好的格式发送字符信息。

核心代码

服务器端:

TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第10张图片

data.h
#include 

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 
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 
#include 
#include 
using namespace std;
//#include 

//从文件读取
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 
#include 

#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 
#include 
#include 
#include 
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);
}

客户端:

TCPIP协议编程:基于UDP协议的局域网聊天工具的研发_第11张图片

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

client.cpp
#include 
#include 
#include 
#include 
#include 

#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 
#include 
#include 
#include 
#include 
// 必须的头文件

/*
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 
#include 
#include 
#include 
#include 

#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();
}

你可能感兴趣的:(TCPIP协议编程:基于UDP协议的局域网聊天工具的研发)