2024.8.19 学习记录 —— 作业

一、TCP机械臂测试

复制代码
#include <myhead.h>

#define SER_PORT 8888          // 与服务器保持一致
#define SER_IP "192.168.0.114" // 服务器ip地址

int main(int argc, const char *argv[])
{
    // 创建文件描述符打开键盘文件
    int fd = open("/dev/input/event1", O_RDONLY);
    if (fd == -1)
    {
        perror("open error");
        return -1;
    }

    // 定义结构体接收键盘文件的数据
    struct input_event ie;

    // 创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("cfd = %d\n", cfd); 

    // 连接到服务器
    // 填充服务器地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;                // 通信域
    sin.sin_port = htons(SER_PORT);          // 服务器端口号
    sin.sin_addr.s_addr = inet_addr(SER_IP); // 服务器ip地址

    // 连接服务器
    if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
        perror("connect error");
        return -1;
    }
    printf("连接服务器成功\n");

    // 准备数据
    char rbuf[5] = {0xff, 0x02, 0x00, 0x10, 0xff};
    unsigned char bbuf[5] = {0xff, 0x02, 0x01, 0x10, 0xff};

    // 发送给服务器,以初始化机械臂
    send(cfd, rbuf, sizeof(rbuf), 0);
    sleep(1);
    send(cfd, bbuf, sizeof(bbuf), 0);
    printf("%#x\n", rbuf[3]);
    printf("%#x\n", bbuf[3]);

    while (1)
    {
        // 接收键盘文件数据
        read(fd, &ie, sizeof(ie));
        switch (ie.code * ie.value)
        {
        case 32: // d键
            rbuf[3] += 1;
            if (rbuf[3] > 90)
            {
                rbuf[3] = 90;
            }
            send(cfd, rbuf, sizeof(rbuf), 0); // 传输数据给机械臂
            break;
        case 30: // a键
            rbuf[3] -= 1;
            if (rbuf[3] < -90)
            {
                rbuf[3] = -90;
            }
            send(cfd, rbuf, sizeof(rbuf), 0); // 传输数据给机械臂
            break;
        case 31: // s键
            bbuf[3] -= 1;
            if (bbuf[3] <= 0)
            {
                bbuf[3] = 0;
            }
            send(cfd, bbuf, sizeof(bbuf), 0); // 传输数据给机械臂
            break;
        case 17: // w键
            bbuf[3] += 1;
            if (bbuf[3] > 180)
            {
                bbuf[3] = 180;
            }
            if (bbuf[3] < 0)
            {
                bbuf[3] = 0;
            }
            send(cfd, bbuf, sizeof(bbuf), 0); // 传输数据给机械臂
            break;

        default:
            break;
        }
        /*
        if (buf == 'd') // 红机械臂右移一度
        {
            rbuf[3] = rbuf[3] + 1; // 修改角度
            printf("%#x\n", rbuf[3]);
            send(cfd, rbuf, sizeof(rbuf), 0); // 传输结果
        }
        if (buf == 'a') // 红机械臂左移一度
        {
            rbuf[3] = rbuf[3] - 1;
            printf("%#x\n", rbuf[3]);
            send(cfd, rbuf, sizeof(rbuf), 0);
        }
        if (buf == 's') // 蓝机械臂上移一度
        {
            bbuf[3] = bbuf[3] + 1;
            printf("%#x\n", bbuf[3]);
            send(cfd, bbuf, sizeof(bbuf), 0);
        }
        if (buf == 'w') // 蓝机械臂下移一度
        {
            bbuf[3] = bbuf[3] - 1;
            printf("%#x\n", bbuf[3]);
            send(cfd, bbuf, sizeof(bbuf), 0);
        }
        if (buf == 'q') // 直接设置
        {
            int val = 0;
            printf("红机械臂增减角度:");
            scanf("%d", &val);        // 获取增减角度
            rbuf[3] = rbuf[3] + val;  // 修改角度
            printf("%#x\n", rbuf[3]); // 传输结果
            getchar();

            printf("蓝机械臂增减角度:");
            scanf("%d", &val);
            bbuf[3] = bbuf[3] + val;
            printf("%#x\n", bbuf[3]);
            getchar();

            send(cfd, rbuf, sizeof(rbuf), 0);
            usleep(100);
            send(cfd, bbuf, sizeof(bbuf), 0);
        }
        buf = 0;
        */
    }

    // 5、关闭套接字
    close(cfd);

    return 0;
}

二、基于UDP的TFTP文件传输

复制代码
#include <myhead.h>
int main(int argc, char const *argv[])
{
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sfd == -1)
    {
        perror("socket error");
        return -1;
    }

    // 下载请求包
    char buf[516] = "";

    short *p1 = (short *)buf; // 操作码
    *p1 = htons(1);

    char *p2 = buf + 2; // 文件名
    strcpy(p2, "5.png");

    char *p4 = p2 + strlen(p2) + 1; // 模式位
    strcpy(p4, "octet");

    int size = 2 + strlen(p2) + strlen(p4) + 2; // 请求包总长

    // 服务器地址信息
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(69);
    sin.sin_addr.s_addr = inet_addr("192.168.0.114");

    // 向服务器发送a下载请求
    sendto(sfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));

    int newfd = 0;
    if ((newfd = open("./5.png", O_WRONLY | O_CREAT | O_APPEND | O_TRUNC, 0664)) == -1)
    {
        perror("open error");
        return -1;
    }

    while (1)
    {
        socklen_t size_sin = sizeof(sin);
        bzero(buf, sizeof(buf)); // 清空buf

        int res = 0; // 接收服务器发送的数据
        if ((res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &size_sin)) == -1)
        {
            perror("recvform error");
            return -1;
        }
        
        if (res <516)
        {
            write(newfd, buf + 4, res - 4);
            *p1 = htons(4);
            sendto(sfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));
            printf("下载结束\n");
            break;
        }
        
        write(newfd, buf + 4, res - 4);                               // 写入数据
        *p1 = htons(4);                                               // 操作码置位 4
        sendto(sfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin)); // 发送ACK
    }

    close(sfd);
    close(newfd);
    return 0;
}

三、基于UDP的聊天室

1、服务器端

复制代码
#include <myhead.h>
#define SER_PORT 6666            // 服务器端口号
#define SER_IP "192.168.179.128" // 服务器ip地址
// 定义结构体用于存储客服端的信息
struct MSG
{
    char type; // 信息类型 'L'表示登录 'T'表示群聊 'Q'表示退出 'S'表示系统消息

    char name[20];
    char msg[256];
};

// 定义链表用于存储不同的客服端信息
struct ADDR
{
    struct sockaddr_in cin;
    struct ADDR *next;
};

// 登录操作的函数
void do_login(int sfd, struct MSG buf, struct ADDR *addr, struct sockaddr_in cin)
{
    // 先遍历链表 将新用户加入群聊的消息发给所有人
    struct ADDR *tmp = addr; // 记录链表头节点
    while (tmp->next != NULL)
    {
        tmp = tmp->next;
        if (-1 == sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&(tmp->cin), sizeof(tmp->cin)))
        {
            perror("sendto error");
        }
    }
    // 将新用户的网络信息结构体 头插入链表
    struct ADDR *pnew = NULL;
    if (NULL == (pnew = (struct ADDR *)malloc(sizeof(struct ADDR))))
    {
        printf("malloc error\n");
        return;
    }
    pnew->cin = cin;
    pnew->next = addr->next;
    addr->next = pnew;
    return;
}

// 群聊操作的函数
void do_chat(int sfd, struct MSG buf, struct ADDR *addr, struct sockaddr_in cin)
{
    // 遍历链表,将群聊消息发给除了自己之外的所有人
    struct ADDR *ptmp = addr;
    while (ptmp->next != NULL)
    {
        ptmp = ptmp->next;
        if (memcmp(&cin, &(ptmp->cin), sizeof(cin)))
        {
            // 不是自己 就发送数据
            sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&(ptmp->cin), sizeof(ptmp->cin));
        }
    }
    return;
}

// 退出操作的函数
void do_quit(int sfd, struct MSG buf, struct ADDR *addr, struct sockaddr_in cin)
{
    // 遍历链表 是自己就将自己在链表中删除
    // 不是自己 就发送 退出群聊的数据
    struct ADDR *ptmp = addr;
    struct ADDR *del = NULL;
    while (ptmp->next != NULL)
    {
        if (memcmp(&(ptmp->next->cin), &cin, sizeof(cin)))
        {
            // 不是自己
            ptmp = ptmp->next;
            strcat(buf.name,"-系统接管");
            sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&(ptmp->cin), sizeof(ptmp->cin));
        }
        else
        {
            // 是自己
            del = ptmp->next;
            ptmp->next = del->next;
            free(del);
            del = NULL;
        }
    }
    return;
}

int main(int argc, char const *argv[])
{
    // 1、创建用于通信的套接字文件描述符
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sfd == -1)
    {
        perror("scoket error");
        return -1;
    }
    printf("sfd = %d\n", sfd); // 3
    // 2、绑定ip地址和端口号
    //  2.1 填充地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;                // 通信域
    sin.sin_port = htons(SER_PORT);          // 端口号
    sin.sin_addr.s_addr = inet_addr(SER_IP); // ip地址

    // 2.2、 绑定
    if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    printf("bind success\n");
    // 3、数据接收
    struct MSG buf; // 定义用于信息接收的变量

    // 定义用于接收客服端网络信息的变量
    struct sockaddr_in cin;          // 接收对端地址信息
    socklen_t addrlen = sizeof(cin); // 接收地址长度

    // 4、创建父子进程用于不同功能
    pid_t pid = 0;
    if (-1 == (pid = fork()))
    {
        perror("fork error");
        return -1;
    }
    if (0 == pid) // 子进程,用于信息的处理
    {
        // 创建保存客户端信息的链表头节点
        struct ADDR *addr;
        if (NULL == (addr = (struct ADDR *)malloc(sizeof(struct ADDR))))
        {
            printf("malloc error\n");
            return -1;
        }
        memset(addr, 0, sizeof(addr));
        addr->next = NULL;

        while (1)
        { // 循环收发数据
            // 清空容器,确保信息准确
            memset(&buf, 0, sizeof(buf));
            memset(&cin, 0, sizeof(cin));
            // 接收客户端发送的消息,存放在msg中
            if (-1 == recvfrom(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&cin, &addrlen))
            {
                perror("recvfrom error");
                return -1;
            }
            switch (buf.type)
            {         // 判断消息中的操作码,根据操作码执行对应操作
            case 'L': // 登录操作
                do_login(sfd, buf, addr, cin);
                break;
            case 'T': // 群聊操作
                do_chat(sfd, buf, addr, cin);
                break;
            case 'Q': // 退出操作
                do_quit(sfd, buf, addr, cin);
                break;
            }
        }
    }
    else // 父进程,用于发送系统信息
    {
        strcpy(buf.name, "系统消息");
        buf.type = 'T';
        while (1) // 循环在终端接收消息
        {
            memset(buf.msg, 0, sizeof(buf.msg));
            printf("输入信息:");
            fgets(buf.msg, 256, stdin);
            buf.msg[strlen(buf.msg) - 1] = 0;
            sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, addrlen);// 向子进程发送信息
        }
    }

    // 4、关闭文件描述符
    close(sfd);
    return 0;
}

2、客服端

复制代码
#include <myhead.h>
#define SER_PORT 6666            // 与服务器保持一致
#define SER_IP "192.168.179.128" // 服务器ip地址

// 用于信息发送的结构体
struct msgTyp
{
    char type;     // 信息类型 L-》注册名 T-》聊天信息 Q-》退出
    char name[20]; // 注册名
    char msg[256]; // 聊天信息
};

int main(int argc, char const *argv[])
{
    // 1、 创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("cfd = %d\n", cfd);

    // 2、信息发送
    // 2.1数据结构体定义
    struct msgTyp buf;
    bzero(&buf, 0);

    // 2.2 填充服务器地址信息结构体
    struct sockaddr_in sin;                  // 接收对端地址信息
    sin.sin_family = AF_INET;                // 服务器的通信域
    sin.sin_port = htons(SER_PORT);          // 服务器的端口号
    sin.sin_addr.s_addr = inet_addr(SER_IP); // 服务器的ip地址
    socklen_t seraddr_len = sizeof(sin);     // 服务器信息结构体大小

    // 2.3 注册
    buf.type = 'L'; // 指定消息类型
    printf("注册用户名:");
    fgets(buf.name, sizeof(buf.name), stdin);
    buf.name[strlen(buf.name) - 1] = 0;
    strcpy(buf.msg, "登录");

    // 向服务器发送登录信息
    sendto(cfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, seraddr_len);

    // 3 创建父子进程用于处理不同工作
    pid_t pid = 0;
    if (-1 == (pid = fork()))
    {
        perror("fork error");
        return -1;
    }
    // 子进程,用于接收信息
    if (0 == pid)
    {
        while (1)
        {
            if (-1 == recvfrom(cfd, &buf, sizeof(buf), 0, NULL, NULL))
            {
                perror("recvfrom error");
                return -1;
            }

            // 打印接收到的信息
            printf("[%s]:%s\n", buf.name, buf.msg);
        }
    }
    else if (0 < pid) // 父进程,用于向其他客服端发送信息
    {
        while (1)
        {
            bzero(&buf, 0); // 清空容器,以保证信息的准确性
            printf("输入信息:");
            fgets(buf.msg, 256, stdin);
            buf.msg[strlen(buf.msg) - 1] = 0;
            if (!strcmp(buf.msg, "quit"))
            {
                buf.type = 'Q';
                strcpy(buf.msg, "退出群聊");
                sendto(cfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, seraddr_len);
                break;
            }
            else
            {
                buf.type = 'T';
                // 发送信息
                sendto(cfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, seraddr_len);
            }
        }
        // 退出子进程
        kill(pid, SIGKILL);
        wait(NULL); // 阻塞回收子进程资源
    }

    // 3、关闭套接字
    close(cfd);
    return 0;
}
相关推荐
爱喝水的鱼丶16 分钟前
SAP-ABAP:条件判断与循环控制语句(7篇)第七篇:性能优化:条件与循环代码的常见性能瓶颈与优化方案
学习·算法·性能优化·sap·abap
小新同学^O^9 小时前
简单学习 --> 模型参数
学习·llm·大模型参数
cdbqss110 小时前
VB2026 菜单生成基类 BqGetMenuStrip
数据库·经验分享·学习·oracle·vb
吃好睡好便好11 小时前
创建魔方矩阵和单位矩阵
开发语言·人工智能·学习·线性代数·matlab·矩阵
星夜夏空9912 小时前
STM32单片机学习(21) —— I2C通信
stm32·单片机·学习
searchforAI13 小时前
B站视频转笔记用哪个工具?2026年四款AI笔记工具对比实测
人工智能·经验分享·笔记·gpt·学习·视频总结·ai笔记
爱上好庆祝14 小时前
学习JS第十一天(JS的进阶)
前端·javascript·学习
yeiweilan15 小时前
AI应用学习
学习
吃好睡好便好15 小时前
矩阵的加减运算
开发语言·人工智能·学习·线性代数·算法·matlab·矩阵
Mister西泽15 小时前
C++ Primer Plus 第六版 编程练习题及详细答案
开发语言·c++·学习·visual studio