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


    任务目标

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

    完成情况

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

    运行效果图

    服务器菜单:

    服务器端口配置:

    查看当前所有账户:

    开启服务器:

    客户端菜单:

    修改IP和端口号:

    注册账号:

    登录:

    查看好友列表(空):

    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 %[^'']", &id, passwd); //接收用户发送的id 和 密码
        //sprintf(passwd,"%s''",passwd1);
        printf("登录判断:%d %s 
    ", id, passwd);
    
        //int size = sizeof(user) / sizeof(user[0]);
    
        for (int i = 0; user[i].id != -1; i++)
        {
            printf("当前 id : %d %s 
    ", user[i].id, user[i].passwd);
            if (user[i].id == id)
            { //id匹配判断
                printf("id == id : %d %s 
    ", 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 = "好友列表: 
    -------
    ";
        sscanf(str, "%d", &id);
        printf("
     --%d 
    ", id);
        for (int i = 0; user[i].id != -1; i++)
        { //先找到用户再user的下标,再通过friends数组反向找好友的user下标,即可获取信息
            if (user[i].id == id)
            {
                printf("匹配到 %d 
    ", user[i].id);
                for (int j = 0; user[i].friends[j].id != -1; j++)
                {
                    printf("user[i].friends[j].id = %d 
    ", 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 
    ", user[k].id, user[k].name, user[k].online);
                        //itoa
                        //st = st + "ID : " + user[k].id + " 用户名: " + user[k].name + " 状态: " + user[k].online + "
    ";
                        st = st + temp;
                    }
                }
                //st = st + '';
                //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 
    ", 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 
    ", 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 
    ", Uid, Fid);
    
        //双向添加好友
        printf("* 0 *
    ");
        int i = 0;
        for (i = 0; user[Uid].friends[i].id != -1; i++)
        {
            if (user[Uid].friends[i].id == uid)
                return -1;
        }
        printf("* 1 *
    ");
        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 *
    ");
        for (i = 0; user[Fid].friends[i].id != -1; i++)
        {
            if (user[Fid].friends[i].id == fid)
                return -1;
        }
        printf("* 3 *
    ");
        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 *
    ");
        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!
    
    ");
        //创建用于监听的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 
    ",tempBuf);
    
            char type;
            //char msg[1024];
            char *msg = new char[1024];
    
            //将收到的信息进行拆分判断
            sscanf(recvBuf, "%c %[^
    ]", &type, msg);
            int res = 0;
    
            printf("消息类型: %c 
    ", type);
            //printf(" Msg: %s 
    ",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 
    ", 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
    ", 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 %[^
    ]", &type2, more);
                printf("-- %c %s --
    ", 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!
    ");
                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
    ",tempBuf);*/
    
            //发送数据
            /*      printf("Please input data: 
    ");
            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
    回车返回", po);
        getchar();
        getchar();
    } //端口配置
    
    void Mainte(User user[])
    {
        system("cls");
        printf("1.查看信息 2.修改信息
    请输入:");
        char ch;
        ch = getch();
        system("cls");
        if ('1' == ch)
            for (int i = 0; user[i].id != -1; i++)
            {
                printf("第%d条记录->ID:%d 用户名:%s 密码:%s 
    ", 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
    ", 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 
    ",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 
    ", 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("%[^
    ]", buf);
        i = reg(user, buf);
        if (i != -1)
        {
            printf("新注册帐号 -> ID:%d 用户名:%s 密码:%s 
    ", user[i].id, user[i].name, user[i].passwd);
        }
        else
            printf("创建失败!回车返回");
        getchar();
        getchar();
    } //分配账号
    
    void MenuShow()
    {
        system("cls");
        printf("***************************************************************************************************************
    ");
        printf(" |>> Server <<| 
    
    ");
        printf(" |>> 1.服务器 端口 配置 <<| 
    
    ");
        printf(" |>> 2.维护客户端个人信息 <<| 
    
    ");
        printf(" |>> 3.开启 服务器 <<| 
    
    ");
        printf(" |>> 4.分 配 账 号 <<| 
    
    ");
        printf(" |>> 5.退 出 <<| 
    
    ");
        printf("***************************************************************************************************************
    ");
    }
    
    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!
    
    ");
        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("***************************************************************************************************************
    
    ");
            printf(" |>> Client <<| 
    
    ");
            printf(" |>> 1.服务器地址和端口配置 <<| 
    
    ");
            printf(" |>> 2.帐号注册 <<| 
    
    ");
            printf(" |>> 3.用户登录 <<| 
    
    ");
            printf(" |>> 4.退出 <<| 
    
    ");
            printf("***************************************************************************************************************
    
    ");
            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!
    
    ");
                //创建用于监听的套接字
                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("%[^
    ]", 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!
    
    ");
        //创建用于监听的套接字
        //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("%[^
    ]",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("暂时无数据!
    ");
        else
            printf("%s 
    ", recvBuf);
    
        if ('q' == recvBuf[0])
        {
            return 1;
            //sendto(sockSrv,"Q",strlen("Q")+1,0,(SOCKADDR*)&addrSrv,len);
            //printf("Chat end!
    ");
        }
    
        //sprintf(tempBuf,"%s say : %s",inet_ntoa(addrSrv.sin_addr),recvBuf);
        //scanf(recvBuf,"%[^'']",tempBuf);
        //sprintf(tempBuf,"temp: 
     %[^'']",recvBuf);
        //printf("temp : 
    %s 
    
    ",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!
    
    ");
        //创建用于监听的套接字
        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: 
    ");
            printf("1.查看好友 2.发送信息 3.接收信息 4.添加好友 5.删除好友 6.退出: 
    ");
            //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 信息
    ");
                scanf("%[^
    ]", 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
    ");
                scanf("%d", &dstid);
                sprintf(sendBuf, "F A %d %d", id, dstid);
                sendM(sockSrv, ipaddr, port, sendBuf, addrSrv);
                break;
            }
            case '5': //删除好友
            {
                int dstid;
                printf("请输入:对方id
    ");
                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("%[^
    ]",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!
    ");
                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!
    ");
                break;
                //printf("Chat end!
    ");
            }
    
            printf("%s 
    ", recvBuf);
    
            //发送数据
        }
        closesocket(sockSrv);
        WSACleanup();
    }
    
    
  • 相关阅读:
    PHP为fopen,file_get_contents等函数请求web地址时增加Http头的方法
    php一些技术要点连接地址
    PHP之open_ssl
    加密解密知识 php非对称加密
    python摸爬滚打之day17----类与类之间的关系
    python摸爬滚打之day16----类的成员
    python摸爬滚打之day15----初识类
    python摸爬滚打之day14----内置函数,递归函数
    python摸爬滚打之day12----生成器, 各种生成式
    python摸爬滚打之day11----函数闭包,迭代器
  • 原文地址:https://www.cnblogs.com/boxker/p/10745403.html
Copyright © 2020-2023  润新知