坐牢第二十九天

news2024/11/26 22:19:28

思维导图

 作业

作业: 运行1个服务器和2个客户端 实现效果: 服务器和2个客户端互相聊天,服务器和客户端都需要使用select模型去实现 服务器要监视2个客户端是否连接,2个客户端是否发来消息以及服务器自己的标准输入流 客户端要监视服务器是否发来消息以及客户端自己的标准输入流 在不开线程的情况下,实现互相聊天

 服务器代码:

#include <myhead.h>
#define SER_PORT 6666          // 端口号
#define SER_IP "192.168.0.151" // 服务器ip地址
// 添加函数
void insert_newfd(int *newfd_arr, int *len, int newfd)
{
    newfd_arr[*len] = newfd;
    (*len)++;
}
// 查询函数
int find_newfd(int *newfd_arr, int len, int newfd)
{
    for (int i = 0; i < len; i++)
    {
        if (newfd_arr[i] == newfd)
        {
            return i;
        }
    }
    return -1;
}
// 删除函数
void remove_newfd(int *newfd_arr, int *len, int newfd)
{
    int tar = find_newfd(newfd_arr, *len, newfd);
    if (tar == -1)
    {
        return;
    }
    int i = -1;
    for (i = tar; i < *len - 1; i++)
    {
        newfd_arr[i] = newfd_arr[i + 1];
    }
    (*len)--;
}

/**********************主函数*********************/
int main(int argc, char const *argv[])
{
    // 1.创建套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    // 参数1表示ipv4网络通信
    // 参数2表示tcp通信方式
    // 参数3表示默认使用一个协议
    if (sfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("socket succes,sfd=%d\n", sfd);
    // 将端口号快速重用
    int reuse = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口快速重用成功\n");
    // 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.将套接字设置成被动监听状态
    if (listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }
    printf("listen success\n");
    // 4.阻塞等待客户端连接请求
    // 4.1定义变量用于接受客户端的信息
    struct sockaddr_in cin;          // 用于接收地址信息
    socklen_t addrlen = sizeof(cin); // 用于接受长度

    // 创建readfds集合
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(sfd, &readfds);
    FD_SET(0,&readfds);//把标准输入流添加进描述符集合
    // 套接字集合数组
    int newfd_arr[128];
    // 数组大小表示客户端连接个数
    int newfd_len = 0;
    while (1)
    {
        fd_set temp = readfds;
        select(FD_SETSIZE, &temp, 0, 0, 0);
        if (FD_ISSET(sfd, &temp) == 1)
        {
            int newfd = accept(sfd, (struct sockaddr *)&cin, &addrlen);
            if (newfd == -1)
            {
                perror("accept error");
                return -1;
            }
            printf("新客户端连接成功\n");
            FD_SET(newfd, &readfds);
            insert_newfd(newfd_arr, &newfd_len, newfd);
        }
        for (int i = 0; i < newfd_len; i++)
        {
            int newfd = newfd_arr[i];
            if (FD_ISSET(newfd, &temp))
            {
                // 4.收数据
                char buf[128] = "";
                int res = read(newfd, buf, 128);
                if (res == 0)
                {
                    printf("有客户端断开连接\n");
                    FD_CLR(newfd, &readfds);
                    remove_newfd(newfd_arr, &newfd_len, newfd);
                    close(newfd);
                    break;
                }
                printf("有客户端发来消息:%s\n", buf);
            }
            if (FD_ISSET(0, &temp))
            {
                // 标准输入流激活,把消息发送给所有客户端
                char buf[128] = "";
                read(0, buf, sizeof(buf));
                buf[strlen(buf) - 1] = 0;
                for (int i = 0; i < newfd_len; i++)
                {
                    int newbuf = newfd_arr[i];
                    send(newbuf, buf, strlen(buf), 0);
                    printf("发送成功\n");
                }
            }
        }
    }
    close(sfd);
    return 0;
}

客户端代码:

#include <myhead.h>
#define SER_PORT 6666      // 服务器端口
#define SER_IP "127.0.0.1" // 客户端IP地址
#define CLI_PORT 8888      // 客户端端口
#define CLI_IP "127.0.0.1" // 客户端IP地址
int main(int argc, char const *argv[])
{
    // 1.创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("cfd=%d\n", cfd); // 3
    // 将端口号快速重用
    int reuse = 1;
    if (setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口快速重用成功\n");
    // 2.绑定ip地址和端口号
    // 2.1填充地址信息结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;                // 通信域
    cin.sin_port = htons(CLI_PORT);          // 端口号
    cin.sin_addr.s_addr = inet_addr(CLI_IP); // ip地址
    // 3.连接到服务器
    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地址
    // 3.2连接服务器
    if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
        perror("connect error");
        return -1;
    }
    printf("连接服务器成功\n");
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(cfd, &readfds);
    FD_SET(0, &readfds); // 把标准输入流添加进
    // 4.数据收发
    char buf[128] = "";
    while (1)
    {
        fd_set temp = readfds;
        select(FD_SETSIZE, &temp, 0, 0, 0);
        if (FD_ISSET(cfd, &temp))
        {
            char buf[128] = "";
            recv(cfd, buf, sizeof(buf), 0);
            printf("%s", buf);
        }
        else
        {
            char buf[128] = "";
            fgets(buf, sizeof(buf), stdin);
            buf[strlen(buf) - 1] = 0;
            if (strcmp(buf, "quit") == 0)
            {
                break;
            }
            // 将数据发送给服务器
            send(cfd, buf, strlen(buf), 0);
        }
    }
    // 5.关闭套接字
    close(cfd);
    return 0;
}

 

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

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

相关文章

nginx-Web 服务端

nginx的简介 Nginx 是一款高性能的 Web 服务器和反向代理服务器。 高并发处理能力&#xff1a;采用异步非阻塞的方式处理请求&#xff0c;能够在高并发场景下快速响应。 轻量级和高效&#xff1a;资源消耗相对较少&#xff0c;启动速度快。 优秀的反向代理和负载均衡功能&a…

2053. 图的bfs遍历

代码 #include<bits/stdc.h> using namespace std; int a[20][20],q[20]; bool f[20]; int main() {int h,t,n,e,x,y,i;cin>>n>>e;for(i1;i<e;i){cin>>x>>y;a[x][y]1;a[y][x]1;}h1;t1;q[1]1;f[1]true;cout<<1<<" ";wh…

qps测试epoll和io_uring

​ 前边我们了解了Reactor模式和Proactor模式&#xff0c;哪个性能更好呢&#xff1f;需要我们进行测试。前边我们用io_uring实现了Proactor模式&#xff0c;io_uring是2019年才加入到Linux内核中的&#xff0c;提供了三个系统调用函数。都有些抽象&#xff0c;我是直接来拿跑的…

LLM驱动的AI Agent框架:引领行业变革的应用探索与未来展望

AI Agent框架&#xff08;LLM Agent&#xff09;&#xff1a;LLM驱动的智能体如何引领行业变革&#xff0c;应用探索与未来展望 1. AI Agent&#xff08;LLM Agent&#xff09;介绍 1.1. 术语 Agent&#xff1a;“代理” 通常是指有意行动的表现。在哲学领域&#xff0c;Agen…

视频直播平台选择服务器需要注意什么?

在当今数字化时代&#xff0c;直播平台已成为连接内容创作者与广大观众的重要桥梁。为了确保直播的流畅性、稳定性和安全性&#xff0c;服务器的选择与配置显得尤为重要。以下是搭建直播平台时&#xff0c;服务器所需具备的关键因素。 一、高性能与可扩展性 直播平台需要处理大…

黑神话悟空四十二项修改器 v1.0

软件简介 黑神话悟空四十二项修改器由风灵月影精心打磨&#xff0c;为《黑神话悟空》这款备受瞩目的游戏量身定制。这款修改器界面简洁、体积小巧、功能强大&#xff0c;它致力于为玩家提供便捷的游戏体验&#xff0c;让您能够根据个人喜好和需求&#xff0c;轻松调整游戏内的…

4-1-6 arduino控制42步进电机(电机专项教程)

4-1-6 arduino控制42步进电机&#xff08;电机专项教程&#xff09; 4-1-6 arduino控制42步进电机NEMA双极性步进电机A4988如何使用arduino连接A4988驱动模块Arduino控制Nema-17步进电机&#xff08;简化版&#xff09;A4988 Vref电压调节&#xff08;具体看视频&#xff09; 4…

Java数组05:Arrays类

本节内容视频链接&#xff1a;Java数组07&#xff1a;Arrays类讲解_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p57&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 Java中的‌Array类是一个针对数组进行操作的工具类&#xff0c;‌提供了排序、‌…

SVG的基本图形:直线、圆、椭圆、矩形、多边形等的元素的使用说明。

1、先上个图看一下效果&#xff1a;这里面有直线、圆、矩形、椭圆、多边形。 SVG 可缩放矢量图形&#xff08;Scalable Vector Graphics&#xff09;。 SVG 使用 XML 格式定义图像。 2、代码实现&#xff1a; <svg width"500" height"200" viewBox&…

Kubernetes 如何给pod的 /etc/hosts文件里面添加条目

创建pod的时候&#xff0c;pod会在其/etc/hosts里面添加一个条目。 [rootmaster ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES dns-test 1/1 R…

【RabbitMQ】高级特性

本文将介绍一些RabbitMQ的重要特性。 官方文档&#xff1a;Protocol Extensions | RabbitMQ 本文是使用的Spring整合RabbitMQ环境。 生产者发送确认(publish confirm) 当消息发送给消息队列&#xff0c;如何确保消息队列一定收到消息呢&#xff0c;RabbitMQ通过 事务机制 和 …

Java重修笔记 第三十八天 String翻转

String翻转 1. 要求将字符串指定的部分进行翻转 public class StringHomework {public static void main(String[] args) {// 要求将字符串指定的部分进行翻转// 例如:abcdef ---> a edcb f 1, 4System.out.print("转换前: ");String s "abcdef";…

Libcity笔记:strnn_encoder.py

1 cal_basetime 2 calc_timeoff 3 encode 所以对于 STRNN来说&#xff0c;它的eval_data的每个元素是&#xff1a;

《Python 异常捕获全解析及 yield 关键字详解》

在 Python 中&#xff0c;异常捕获是一种处理程序运行时错误的机制&#xff0c;它可以使程序在出现错误时继续运行&#xff0c;而不是崩溃。以下是对 Python 中异常捕获的详细介绍&#xff0c;包括try、except、else、finally关键字以及对yield关键字的介绍和案例。 一、异常捕…

深入解析FSD烟火识别算法:全套源码与应用实例

一、背景 随着智能监控技术的不断发展&#xff0c;烟火识别&#xff08;Fire Smoke Detection, FSD&#xff09;算法在安防领域得到了广泛应用。传统的火灾探测方法主要依赖于温度传感器和烟雾报警器&#xff0c;这些方法在反应速度和准确性上存在一定局限。尤其是在广阔的户外…

rocketmq 同步复制,异步复制,同步刷盘,异步刷盘详解

一、刷盘模式 同步刷盘&#xff1a; 在返回写成功状态时&#xff0c;消息已经被写入磁盘。具体流程是&#xff0c;消息写入内存的PAGECACHE后&#xff0c;立刻通知刷盘线程刷盘&#xff0c;然后等待刷盘完成&#xff0c;刷盘线程执行完成后唤醒等待的线程&#xff0c;返回消息…

Visual C++ 微软常用运行库合集|dll报错必装

前言 Microsoft Visual C Redistributable&#xff08;简称MSVC&#xff0c;VB/VC&#xff0c;系统运行库&#xff09;是Windows操作系统应用程序的基础类型库组件。此版Visual C运行库组件合集&#xff08;微软常用运行库合集&#xff09;由国内封装爱好者Dreamcast打包而成&…

VulnStack1-内网渗透记录

网络结构 kali192.168.20.145windows7192.168.20.148/192.168.52.1432008192.168.52.138Win2k3192.168.52.130 三台虚拟机IP初始状态固定为192.168.52.0/24网段&#xff0c;所以将仅主机模式的网卡设置为192.168.52.0/24网段 漏洞利用 phpStudy 首先查看windows7的web服务…

个人理解—uboot启动过程(1)

在前文关于MKCONFIG的常用配置参数与链接脚本中逐渐的引入了通过uboot的文件启动校验头引入了uboot的汇编部分&#xff0c;该部分是为了去启动后续的uboot的c语言部分&#xff0c;但是c语言是需要使用到内存的&#xff0c;所以可用理解为&#xff1a;该汇编部分的主要目的就是为…

python异步编程-channels使用,创建websocket服务

目录 channels介绍准备工作创建python虚拟环境安装channels安装django安装daphne创建django项目创建chat应用 配置instance项目简单聊天室页面在chat应用中创建模板base.htmlroom.html 添加视图添加路由添加urls.py项目路由添加chat转发路由启动同步服务器 搭建websocket服务创…