网络编程练习:UDP聊天室

news2024/9/20 21:34:35

 【1】服务器代码

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "head.h"

// 服务器-------------------------------------------------------------------------》短信的接收方

/*创建一个空的单向链表*/
Node_p Create();

/*登录,聊天,退出*/
void login(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr);
void chat(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr);
void quit(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr);

int main(int argc, char const *argv[])
{
    int fd_s;
    // 1.创建数据报套接字(socket)------------------》有手机
    fd_s = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd_s < 0)
    {
        perror("soc err\n");
        return -1;
    }
    // printf("%d\n", fd_s);
    // 2.指定网络信息--------------------------------------》有号码
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    saddr.sin_addr.s_addr = INADDR_ANY;
    int len = sizeof(caddr);

    // 3.绑定套接字(bind)------------------------------》绑定手机
    if (bind(fd_s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err\n");
        return -1;
    }
    // printf("bind ok\n");

    printf("欢迎使用欢欢聊天室\n");

    Msg msg;
    Node_p p = Create(); // 创建空链表

    pid_t pid;
    pid = fork(); // 创建新进程
    if (pid < 0)
    {
        perror("fork err\n");
        return -1;
    }
    else if (pid == 0)
    {
        fgets(msg.text, sizeof(msg.text), stdin);
        if (msg.text[strlen(msg.text) - 1] == '\n')
            msg.text[strlen(msg.text) - 1] = '\0';
        msg.type = 'C';
        strcpy(msg.name, "server");

        sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);
    }
    else
    {
        // 4.接收、发送消息(recvfrom sendto)-------》收短信
        while (1)
        {
            int ret;
            ret = recvfrom(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&caddr, &len);
            if (ret < 0)
            {
                perror("recv err\n");
                return -1;
            }
            // printf("addr: %s  port: %d\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
            if (msg.type == 'L')
            {
                // printf("addr: %s  port: %d\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
                printf("<%s> 已登录\n", msg.name);
                sprintf(msg.text, "<%s> 已登录", msg.name);
                login(fd_s, msg, p, caddr);
            }
            else if (msg.type == 'C')
            {

                printf("[%s]: %s\n", msg.name, msg.text);
                chat(fd_s, msg, p, caddr);
            }
            else if (msg.type == 'Q')
            {
                sprintf(msg.text, "<%s> 已下线", msg.name);
                printf("<%s> 已下线\n", msg.name);
                quit(fd_s, msg, p, caddr);
            }
        }
    }
    // 5.关闭套接字(close)----------------------------》接收完毕
    close(fd_s);
    return 0;
}

/*创空表*/
Node_p Create()
{
    Node_p p = (Node_p)malloc(sizeof(Node_t)); // 开辟一个节点大小的堆区空间
    if (NULL == p)                             // 开辟失败
    {
        printf("malloc lost");
        return NULL;
    }
    p->next = NULL; // 初始化头节点指针域
    return p;       // 开辟成功,返回
}

/*登录*/
void login(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr)
{
    while (p->next != NULL)
    {
        p = p->next;
        sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
    }

    /*创建新的节点*/
    Node_p p_new = (Node_p)malloc(sizeof(Node_t));
    if (p_new == NULL)
    {
        perror("malloc err\n");
        return;
    }

    /*初始化节点*/
    p_new->addr = caddr;
    p_new->next = NULL;

    /*将新节点连接到链表中*/
    p->next = p_new;
    // p = p_new;
    return;
}

/*聊天*/
void chat(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr)
{
    while (p->next != NULL)
    {
        p = p->next;
        if ((memcmp(&(p->addr), &caddr, sizeof(caddr))) == 0)
        {
            continue;
        }
        sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
    }
}

/*退出*/
void quit(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr)
{
    while (p->next != NULL)
    {
        if ((memcmp(&(p->next->addr), &caddr, sizeof(caddr))) == 0)
        {
            Node_p p_del = NULL;
            p_del = p->next;
            p->next = p_del->next;
            free(p_del);
            p_del = NULL;
            continue;
        }
        else
        {
            p = p->next;
            sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
        }
    }
    return;
}

【2】客户端代码 

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include "head.h"
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

// 客户端---------------------------------------------------------------------------》短信的发送方

struct sockaddr_in saddr;
int len = sizeof(saddr);

int main(int argc, char const *argv[])
{
    // 1.创建数据报套接字(socket)------------------》有手机
    int fd_c;
    fd_c = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd_c < 0)
    {
        perror("soc err\n");
        return -1;
    }
    // printf("%d\n", fd_c);
    // 2.指定网络信息--------------------------------------》有对方号码
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    saddr.sin_addr.s_addr = inet_addr("192.168.31.187");

    Msg msg;
    msg.type = 'L';
    printf("欢迎使用欢欢聊天室\n");
    printf("请输入用户名:");
    fgets(msg.name, N, stdin);
    if (msg.name[strlen(msg.name) - 1] == '\n')
        msg.name[strlen(msg.name) - 1] = '\0';

    sendto(fd_c, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, sizeof(saddr));

    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err");
        exit(-1);
    }
    else if (pid == 0)
    {
        while (1)
        {
            if (recvfrom(fd_c, &msg, sizeof(msg), 0, NULL, NULL) < 0)
            {
                perror("recvfrom err");
                return -1;
            }
            if (msg.type == 'L')
                printf("%s\n", msg.text);
            else if (msg.type == 'C')
                printf("[%s]:%s\n", msg.name, msg.text);
            else if (msg.type == 'Q')
                printf("%s\n", msg.text);
        }
    }
    else
    {
        while (1)
        {
            fgets(msg.text, sizeof(msg.text), stdin);
            if (msg.text[strlen(msg.text) - 1] == '\n')
                msg.text[strlen(msg.text) - 1] = '\0';
            if (strcmp(msg.text, "quit") == 0)
            {
                msg.type = 'Q';
                sendto(fd_c, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);
                kill(pid, SIGKILL);
                wait(NULL);
                exit(-1);
            }
            else
            { 
                msg.type = 'C';
            }
            // 发送消息
            sendto(fd_c, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);
        }
    }
    close(fd_c);

    return 0;
}

今天的分享就到这里结束啦,如果有哪里写的不好的地方,请指正。
如果觉得不错并且对你有帮助的话点个关注支持一下吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SA8155P】AIS Camera相关内容的简单介绍

高通车载相机模块(AIS,Automotive lmage System)是专门针对车载系统特性而设计的一套车载视觉架构,可用于AVM、RVC、DMS等常见车载视频应用开发。车载Camera系统的图像大部分是给自动驾驶等使用,更多考虑的是远距离传输、多摄像头图像处理等场景。 本文仅对AIS Camera相关…

MySQL的登陆错误:ERROR 1049 (42000): Unknown database ‘root‘

MySQL的登陆错误&#xff1a;ERROR 1049 (42000): Unknown database ‘root’ 安装MySQL的时候&#xff0c;到网上查的命令行登陆MySQL的方法都是mysql -u root -p password mysql -r root -p 123456但是奇怪的是这条命令我输进去死活都不对&#xff0c;它都会要求再输入一遍…

21、Tomato

难度 低(个人认为中) 目标 root权限 一个flag 使用VMware启动 kali 192.168.152.56 靶机 192.168.152.66 信息收集 端口信息收集 可以看到有个ftp服务&#xff0c;2211实际是ssh协议端口&#xff0c;80、8888是一个web服务 web测试 80端口显示一个tomato 查看源码给了一些…

从0开始学ARM

1. ARM模式和寄存器 1.1 ARM处理器工作模式 Cortex系列之前的ARM处理器工作模式一共有7种。 1.1.1 工作模式 Cortex系列的ARM处理器工作模式有8种&#xff0c;多了1个monitor模式&#xff0c;如下图所示&#xff1a; ARM之所以设计出这么多种模式出来&#xff0c;就是为了…

三菱变频器RS-485 端子的接线和构成

RS-485 端子排列 RS-485 端子接线方法 RS-485 的计算机1台、变频器1台时 RS-485 的计算机1台、变频器n台(多台)时 通讯运行的初始设定 1、为使变频器和计算机进行 RS-485 通讯&#xff0c;进行必要的设定。 2、通讯分为使用变频器的PU接口的通讯和使用RS-485端子的通讯。 3、…

搜索引擎onesearch3实现解释和升级到Elasticsearch v8系列(四)-搜索

搜索 搜索内容比较多&#xff0c;onesearch分成两部分&#xff0c;第一部分&#xff0c;Query构建&#xff0c;其中包括搜索词设置&#xff0c;设置返回字段&#xff0c;filter&#xff0c;高亮&#xff1b;第二部分分页和排序。第一部分是映射引擎负责&#xff0c;映射通用表…

SAP B1 流程实操 - 营销单据销售部分(下)

背景 在 SAP B1 中&#xff0c;最重要的模块就是【销售】&#xff0c;企业可能不涉及生产和库存&#xff08;贸易公司&#xff09;&#xff0c;甚至不涉及采购&#xff08;服务业&#xff09;&#xff0c;但是一定会有基本的 销售。本文中我们讲解 销售 模块的基本核心&#x…

2024年最新苹果cms升级插件【泛目录专用】

苹果CMS是一款专为视频内容管理而设计的系统&#xff0c;近年来在视频站点搭建中逐渐成为热门选择。其直观的用户界面和灵活的管理功能&#xff0c;使得无论是新手还是专业开发者都能轻松上手。 苹果CMS提供了多种主题和模板&#xff0c;用户可以根据自身需求进行定制&#xf…

Python画笔案例-054 绘制流光溢彩动画

1、绘制流光溢彩动画 通过 python 的turtle 库绘制 流光溢彩动画&#xff0c;如下图&#xff1a; 2、实现代码 绘制流光溢彩动画&#xff0c;以下为实现代码&#xff1a; """本程序实现流光溢彩的动画效果 """ from turtle import * from color…

from tqdm.auto import tqdm用法详细介绍

tqdm 是一个 Python 库&#xff0c;用于在长时间运行的任务中显示进度条。tqdm.auto 是 tqdm 的一个版本&#xff0c;能够自动适配输出环境&#xff08;如 Jupyter Notebook、命令行等&#xff09;&#xff0c;以确保进度条在各种环境下显示正确。下面是 tqdm.auto 的详细用法介…

【刷题】杨辉三角

目录 杨辉三角题目描述解题思路解题代码 相同的树题目描述解题思路 二叉树的层序遍历题目描述解题思路解题代码从底层层序遍历 二叉树的最近公共祖先题目描述解题思路 从前序与中序遍历序列构建二叉树题目描述解题思路 从后序与中序遍历序列构建二叉树题目描述解题思路 根据二叉…

SAP-MM-变式的设置

1、报表变式 业务需求: 业务人员查询报表时有些值是需要经常输入的,能不能设置成默认值?能不能设置成每次进入报表不选择变式直接是默认值? 解决措施: 1、事物码:MB51 以MB51物料凭证查询为例,其他报表自行举一反三 2、设置变式 首先进入MB51入下图 上图是没有选…

任天堂发言人:不会透露起诉《幻兽帕鲁》开发商细节

任天堂在昨天突然宣布将起诉《幻兽帕鲁》开发商 Pocketpair&#xff0c;除了引起许多玩家不满外&#xff0c;更多的是所有人的疑惑&#xff1a;因为实际上大家内心里觉得任天堂出手是理所当然的&#xff0c;但是为什么是在游戏发布数月后才选择起诉&#xff1f;此次诉讼是“专利…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)2.1-2.2

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第二周 深度卷积网络&#xff1a;实例探究&#xff08;Deep convolutional models: case studies&#xff09;2.1 为什么要进行实例探究&#xff1f;&#xff08;Why look at case studies?&…

Python编码系列—Python外观模式:简化复杂系统的快捷方式

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

生信初学者教程(八):数据收集

文章目录 数据分布表达谱数据最终数据分布自动下载GSE14520下载GSE149614下载其它数据在确定研究疾病为肝细胞癌**(Liver Hepatocellular Carcinoma: HCC)**后,系统地进行了文献回顾,专注于搜索与HCC相关的荟萃分析文章,以获取该领域的研究动态和已有成果。为了支持的研究…

卡车配置一键启动无钥匙进入手机控车

‌ 卡车智能一键启动无钥匙进入手机控车&#xff0c;通过手机应用程序与汽车内置硬件、软件的无线通信&#xff0c;实现对汽车的远程控制‌。 卡车改装一键启动的步骤包括安装门把手的感应装置、拆卸仪表台和门板&#xff0c;取出内部的待接线束&#xff0c;并将一键启动…

MySQL高阶1875-将工资相同的雇员分组

目录 题目 准备数据 分析数据 题目 编写一个解决方案来获取每一个被分配到组中的雇员的 team_id 。 返回的结果表按照 team_id 升序排列。如果相同&#xff0c;则按照 employee_id 升序排列。 这家公司想要将 工资相同 的雇员划分到同一个组中。每个组需要满足如下要求&a…

springboot结合p6spy进行SQL监控

1.学习p6spy的相关链接 英文文档&#xff1a;Integrating P6Spy — p6spy 3.9.2-SNAPSHOT documentationhttps://p6spy.readthedocs.io/en/latest/integration.html github链接&#xff1a;GitHub - p6spy/p6spy: P6Spy is a framework that enables database data to be sea…

solana项目counter,测试过程中执行报错记录分享

跟随HackQuest部署counter项目&#xff0c;使用 Solana 官方提供的 playgroud 。这个平台让我们的部署和测试过程变得更加简便高效。 合约代码 lib.rs中复制以下代码 use anchor_lang::prelude::*; use std::ops::DerefMut;declare_id!("CVQCRMyzWNr8MbNhzjbfPu9YVvr97…