一个基于TCP/IP的小项目,实现广播消息的功能。(超详细版)

2023-05-16

1.结合现状 功能分析

该功能基于上个项目的改进,主要是通过对服务器端代码的修改,以及对客户端作少许修改,实现开启多客户端时,一个客户端发送消息,达到对所有客户端广播的效果。可参考网吧里的点歌系统,比如某某用户在网吧点了一首歌,其他用户电脑的左下角都会弹出一个某某用户点了一首七里香,或者游戏里面的频道聊天,每个人发完消息后,聊天室里的人都知道你发的消息了,就像下图一样,这也正是做这个功能的初衷吧。

 

2.图说代码

  代码细说:

  服务器里面定义了两个字段,一个用于服务器与客户端的连接,另一个目的在于做一个接受广播的客户端表单。 

  服务器里有四个函数,分别对应着客户端监听、客户端连接、接受客户端消息和发报广播。

  客户端定义了一个字段

  客户端包含4个函数,分别为建立连接,接受广播,非后台的发送消息线程、发送消息四部分

  操作流程:

 1)开启服务器,即黑线①的过程,启动监听。

 2)开启客户端,自动根据IP连接服务器,即绿线②。

 3)客户端1发送消息至服务器,服务器广播消息至客户端2,即红线③。

 

3.代码实现

服务器端包含一个主函数和一个ServerControl类

主函数:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ServerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // 调用构造函数,使用Start方法
            ServerControl server = new ServerControl();
            server.Start();

            Console.ReadKey();
        }
    }
}  

ServerControl类:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ServerTest
{
    public class ServerControl
    {
        // 声明变量(使用Socket需using System.Net.Sockets;)
        private Socket serverSocket;
        // 声明一个集合
        private List<Socket> clientList;

        // 自定义有参构造函数,包含两个方法(IP地址,流程传输方式,TCP协议)
        public ServerControl()
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientList = new List<Socket>();
        }

        // 创建启动方法(IPEndPoint用于指定地址及端口初始化,需using System.Net;)
        public void Start()
        {
            // 服务器启动
            // 绑定IP地址(为任意IP)与端口(设置为12345)
            serverSocket.Bind(new IPEndPoint(IPAddress.Any,12345));
            serverSocket.Listen(10);
            Console.WriteLine("服务器启动成功");

            // 开启线程:目的实现服务器和客户端一对多连接
            Thread threadAccept = new Thread(Accept);
            threadAccept.IsBackground = true;
            threadAccept.Start();
        }
         // Accept方法测试:接收客户端连接
        private void Accept()
        {
            // 接收客户端方法,会挂起当前线程(.RemoteEndPoint表示远程地址)
            Socket client = serverSocket.Accept();
            IPEndPoint point = client.RemoteEndPoint as IPEndPoint;
            Console.WriteLine(point.Address + "[" + point.Port + "] 连接成功!");
            clientList.Add(client);

            // 开启一个新线程线程,实现消息多次接收
            Thread threadReceive = new Thread(Receive);
            threadReceive.IsBackground = true;
            threadReceive.Start(client);

            // 尾递归
            Accept();
        }

        // Receive方法的使用测试
        // 接收客户端发送过来的消息,以字节为单位进行操作
        // 该方法会阻塞当前线程,所以适合开启新的线程使用该方法
        // Accept()中将Receive作为线程传递对象,所以要注意一点,使用线程传递对象只能是object类型的!!
        private void Receive(object obj)
        {
            // 将object类型强行转换成socket
            Socket client = obj as Socket;

            IPEndPoint point = client.RemoteEndPoint as IPEndPoint;

            // 此处的异常抛出主要针对客户端异常的问题
            // 比如,客户端关闭或者连接中断
            // 程序会停留在int msgLen = client.Receive(msg);这段代码,而导致无法继续往下走
            try
            {
                byte[] msg = new byte[1024];
                // 实际接收到字节数组长度,该方法会阻塞当前线程,即(client.Receive(msg)开始挂起)
                // 同时,这里还是尾递归挂起处
                int msgLen = client.Receive(msg);
                // 将msg装换成字符串
                string msgStr = point.Address + "[" + point.Port + "]:" + Encoding.UTF8.GetString(msg, 0, msgLen);
                Console.WriteLine(msgStr);

                // 调用广播函数
                Broadcast(client,msgStr);
                // 尾递归实现多条消息的接收;和while同理。
                Receive(client);
            }
            catch
            {
                Console.WriteLine(point.Address + "[" + point.Port + "]积极断开");
                // 若客户端中断,则将他在集合中删除
                clientList.Remove(client);
            }
        }

        private void Broadcast(Socket clientOther,string msg)
        {
            foreach(var client in clientList)
            {
                if(client == clientOther)
                {
                    // 不做任何响应
                }
                else
                {
                    client.Send(Encoding.UTF8.GetBytes(msg));
                }
            }
        }
    }
}  

客户端包含一个主函数和一个ClientControl类

主函数:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClientTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // 调用构造函数
            ClientControl client = new ClientControl();
            // 输入本机IP与端口号
            client.Connect("129.211.7.135", 12345);
            // 启动send方法
            client.Send();

            Console.ReadKey();
        }
    }
}  

ClientControl类:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ClientTest
{
    public class ClientControl
    {
        // 声明变量
        private Socket clientSocket;

        // 自定义有参构造方法((IP地址,流程传输方式,TCP协议))
        public ClientControl()
        {
            clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
        }

        // 创建通过IP与端口号连接的方法
        public void Connect(string ip,int port)
        {
            clientSocket.Connect(ip, port);
            Console.WriteLine("连接服务器成功");

            // 客户端接收服务器消息的线程
            Thread threadReceive = new Thread(Receive);
            threadReceive.IsBackground = true;
            threadReceive.Start();
        }

        // 用于测试服务器向客户端返回一条消息
        private void Receive()
        {
            while(true)
            {
                try
                {
                    // 用于接收服务器的回复信息
                    byte[] msg = new byte[1024];
                    int msgLen = clientSocket.Receive(msg);
                    Console.WriteLine("服务器:"+Encoding.UTF8.GetString(msg,0,msgLen));
                }
                // 异常处理方法
                catch
                {
                    Console.WriteLine("服务器积极拒绝!!");
                    // 退出while循环
                    break;
                }
            }
        }

        // Send方法测试:即发送消息,以字节为单位
        public void Send()
        {
            Thread threadSend = new Thread(ReadAndSend);
            // 将该线程设为非后台线程。
            // threadSend.IsBackground = true;
            threadSend.Start();
        }

        private void ReadAndSend()
        {
            // 提示操作方法
            Console.WriteLine("请输入发送至服务器的内容或者输入quit退出");
            // 输入内容
            string msg = Console.ReadLine();
            // 非退出情况下操作方式,使用while可以持续不断的接收用户输入
            while (msg != "quit")
            {
                clientSocket.Send(Encoding.UTF8.GetBytes(msg));
                msg = Console.ReadLine();
            }
        }
    }
}  

4.实现过程

该过程将服务器部署至腾讯云服务器,分别在腾讯云服务器和本地PC上各开启2个客户端演示广播过程。

若没有多余的电脑或者云服务器,可将客户端主函数里面的IP地址代码改为127.0.0.1,即可完成本地测试。

 

转载于:https://www.cnblogs.com/WeiMLing/p/11332921.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个基于TCP/IP的小项目,实现广播消息的功能。(超详细版) 的相关文章

  • P900数传端口定义

    P900数传端口引脚
  • P900数传配置教程

    typec线连接后按住SB2不松手后按住SB1 xff0c 分别松开SB2 SB1 xff0c 点击XCTU软件 http www pc6 com softview SoftView 602005 html 大写的 AT amp F7 设置
  • ubuntu查看软件安装路径

    ubuntu怎么查看软件安装位置在哪 服务器 亿速云 1 执行程序查看 在终端使用type执行软件程序查看 type google chrome 2 通过进程查看对应的软件程序 在终端使用以下命令查看所有进程名 ps e 再使用以下过滤命令
  • Ubuntu中wine程序安装windows软件中文乱码问题

    Ubuntu中wine程序安装windows软件中文乱码如何解决 1 安装wine sudo apt install wine 2 安装中文程序方法 下载exe文件在命令行执行 wine 文件名 exe 3 中文乱码原因分析 查看 home
  • ubuntu通过Trickle,wondershaper限制网速(上传下载速度)

    原文连接 xff1a https www ngui cc 51cto show 727932 html action 61 onClick 在Linux下没有Windows使用360那样去限制某个软件的速度 但是通过Trickle可以设置某
  • Ubuntu 16.04 重置密码(忘记密码)

    Ubuntu 16 04 重置密码 xff08 忘记密码 xff09 http blog topspeedsnail com archives 6042 忘记了你的Ubuntu用户密码 xff0c 登录不了系统 xff1b 不要紧 xff0
  • ubuntu下socket通信

    第一部分为C 43 43 实现 xff0c 第二部分为python实现 第一部分 该socket 的功能是在客户端输入了两个浮点数组成的字符串 xff0c 在服务端接受后将其转换为浮点数输出 xff0c 统一时刻只能有一个客户端连接 服务端
  • 关于螺旋桨的计算

    关于螺旋桨的计算 转载 http blog sina com cn s blog 4c2264b80100086z html 发给大家一些关与螺旋桨的计算公式 2007 02 07 13 08 46 功率 xff08 W xff09 直径
  • PID参数整定快速入门(调节器参数整定方法)

    转载地址 http yunrun com cn tech 440 html PID 参数整定方法很多 xff0c 常见的工程整定方法有临界比例度法 衰减曲线法和经验法 云南昌晖仪表制造有限公司以图文形式介绍以临界比例度法和衰减曲线法整定调节
  • STM8 CAN总线的IdMask模式的讲解

    http www stmcu org article id 328212 STM8 CAN总线的IdMask模式的讲解 发布时间 xff1a 2016 08 27 来源 xff1a ST社区 标签 xff1a STM8 CAN总线 IdMa
  • gitlab使用http方式提交代码不输入密码

    gitlab使用http方式提交代码不输入密码 记得这个问题很久之前就折腾过 xff0c 今天从gitlab上克隆一个仓库 xff0c 第一时间肯定是想着使用ssh公私钥进行验证 xff0c 这样以后也不需要再输入密码 xff0c 可是公司
  • STM32运行时程序卡在B.处

    STM32运行时程序卡在B 处的问题处理的一天多 xff0c 终于找到原因 1 xff0c 表现 我所使用的芯片是stm32f427vit6 xff0c stm32f4系列芯片外设多数都相同 xff0c 407 xff0c 405的 用户也
  • Keil 查看文件路径的方法

    目录 方法一 xff1a 方法二 xff1a 方法一 xff1a 在工程种选择任意一个文件 xff0c 然后点击右键 xff0c 选择 34 Option for File 34 就可以看到这个文件的路径了 方法二 xff1a 在文件框种右
  • Linux下CMake简明教程

    CMake是开源 跨平台的构建工具 xff0c 可以让我们通过编写简单的配置文件去生成本地的Makefile xff0c 这个配置文件是独立于运行平台和编译器的 xff0c 这样就不用亲自去编写Makefile了 xff0c 而且配置文件可
  • unity3d TextMeshPro使用中文字体(秒懂)

    1 打开C Windows Fonts 目录选择中文字体 2 将选中的字体拖拽到Unity编辑器中 3 将已下这段文字保存至zh cn txt文件 注意编码格式为Unicode xff0c 不然会出现乱码 并且拖入Unity编辑器 的一是了
  • Windows下cmd命令行远程传输sftp命令

    sftp 用户名 64 ip地址
  • laravel 500 Server Error,完美解决

    在安装laravel项目后 xff0c 首次打开laravel出现 解决方案 xff1a 1 打开配置文件 laravel config app php 3 找到 39 debug 39 项 设置为 true 4 刷新网页 抛出运行异常 x
  • ubuntu下C++两种方法解析json

    第一种 用jsoncpp xff0c 不过本人目前不知道如何在clion里面使用 xff0c 只知道在命令行g 43 43 使用 xff0c 哪位知道如何在clion里使用可以告诉我 xff0c 谢谢 如下步骤本人操作过两边 xff0c 所
  • unity3d鼠标控制物体 移动 旋转 缩放

    需求 xff1a 制作一个鼠标中键移动缩放和鼠标右键旋转的功能 xff08 鼠标右键旋转可以自行改成鼠标左键旋转 xff09 效果图 xff1a 1 新建一个名为Target的立方体cube 2 新建一个材质球 Yellow颜色的并挂载到T
  • Centos Apache2设置禁止浏览目录,绝对生效。

    1 打开httpd配置文件 vi etc httpd conf httpd conf 2 找到 Options Indexes FollowSymLinks 注释掉 xff0c 并在下面添加一行 Options None Options I

随机推荐

  • Ubuntu查看某端口是否开放

    1 例如查看80端口是否开放 xff0c 输入 lsof i 端口号 xff0c 如果没有信息出现则说明该端口还未开放 lsof i 80 telnet 192 168 0 1 80 2 也可以通过以下命令 xff0c 查看所有开放的端口
  • 集群和分布式的区别,还不理解的你打我!!!

    1 老师布置作业 xff0c 让你抄10遍白居易的 长恨歌 xff0c 抄一份需要5分钟 xff0c 10份需要50分钟 xff0c 这时你觉得要是有9个人帮我抄另外9份 xff0c 那你5分钟就能交作业了 xff0c 这就是集群处理 2
  • windows下查找并关闭端口

    1 查找端口 8080 gt netstat ano findstr 8080 找到8080端口对应的pid 19060 2 关闭8080端口 gt taskkill f pid 19060
  • Unity3D 制作调色板

    一个很好用的调色板 源码 xff1a http websol cn 2021 01 27 unity e8 b0 83 e8 89 b2 e6 9d bf e6 ba 90 e7 a0 81
  • vs2017生成C++/C语言的DLL以及调用 极简讲解 秒懂

    为了尽可能缩减文字描述 xff0c 减少阅读疲劳 xff0c 就直接上图了 1 VS2017下C 43 43 创建dll动态链接库 2 VS2017下C语言代码创建dll动态链接库 xff08 导出方式较于C 43 43 有点差别 xff0
  • Unity页面滑动Slider

    第一步 xff1a 创建三个Image xff08 或者多个都行 xff09 xff0c 并且设置Canvas的CanvasScaler脚本组件UI Scale Mode和Reference Resolution的值 设置Canvas 第二
  • linux的TCP连接数量真的不能超过65535个吗?

    原文链接 xff1a https blog csdn net daocaokafei article details 115410761 首先 xff0c 问题中描述的65535个连接指的是客户端连接数的限制 在tcp应用中 xff0c s
  • 关于网页实现串口或者TCP通讯的说明

    概述 最近经常有网页联系我 xff0c 反馈为什么他按我说的方法 xff0c 写的HTML代码 xff0c 无法在chrome网页中运行 这里我统一做一个解释 xff0c 我发现好多网页并没有理解我的意思 其实 xff0c 要实现在HTML
  • Intel RealSense(实感技术)概览

    Intel RealSense 实感技术 概览 1 Reply 版权声明 xff1a 本文系本站作者自己翻译整理 xff0c 欢迎转载 xff0c 但转载请以超链接形式注明文章来源 planckscale info 作者信息和本声明 xff
  • postman安装使用教程

    无聊的夜晚 xff0c 没有酒喝 xff0c 也没妹子陪 xff0c 闲来没事研究下postman xff0c 之前接触过有点 xff0c 还不错的工具 先从最基本的开始 postman是谷歌的一款非常好用的工具 xff0c 可用来做手工的
  • 接口测试 requests的身份认证方式

    requests提供多种身份认证方式 xff0c 包括基本身份认证 netrc 认证 摘要式身份认证 OAuth 1 认证 OAuth 2 与 OpenID 连接认证 自定义认证 这些认证方式的应用场景是什么呢 xff1f 身份认证的定义
  • 使用libcurl提交POST请求

    最近在学习libcurl xff0c 并利用它提交POST请求 xff0c 可是返回的响应总是无从验证该次POST请求是否成功提交了 1 先看下根据firebug提交的一次成功的请求 xff0c 这里以login我喜欢上的xiami为例 x
  • TX2安装Realsense -L515相机并在ros下 运行yolo 总结(3)

    前面提到可以移植yolov4到平台上 这里给出几个参考链接 xff0c 重在学习移植方法 xff1a 首先是大佬的 xff1a https span class token operator span span class token op
  • VS2013 配置使用微软开源sdk: C++ REST SDK 及运行官方的 JSON例子

    转至 https blog csdn net sdsabc2000 article details 53706632 utm medium 61 distribute pc relevant none task blog BlogComme
  • Python爬虫学习4:requests.post模拟登录豆瓣(包括获取验证码)

    1 在豆瓣登录网页尝试登录后打开开发者工具 xff0c 可以查找后去Headers和Form Data信息 2 实现代码 import requests import html5lib import re from bs4 import B
  • STM32 | STM32CubeMX基础之USART

    一 USART框图 功能引脚 TX xff1a 发送引脚 xff0c Usart1一般对应PA9 RX xff1a 接收引脚 Usart1一般对应PA10 SW RX xff1a 数据接收引脚 xff0c 只用于单线和智能卡模式 xff0c
  • Android CMake 编译传递宏定义参数

    在做 C 43 43 需求开发时经常会遇到用宏定义来区分不同版本 不同平台的功能 xff0c 如下所示 xff1a ifdef DEBUG 调用 debug 版本方法 elif RELEASE 调用 release 版本方法 endif 在
  • FreeRTOS高级篇2---FreeRTOS任务创建分析

    在FreeRTOS基础系列 FreeRTOS系列第10篇 FreeRTOS任务创建和删除 中介绍了任务创建API函数xTaskCreate xff0c 我们这里先回顾一下这个函数的声明 xff1a BaseType t xTaskCreat
  • 调用百度OCR API实现身份证文字识别

    调用百度OCR API实现身份证文字识别 通过调用百度OCR的两个接口 xff0c 实现身份证图像识别 首先要在百度云注册账号 xff0c 并创建应用 xff0c 以获取AppID xff0c API Key xff0c Secret Ke
  • 一个基于TCP/IP的小项目,实现广播消息的功能。(超详细版)

    1 结合现状 功能分析 该功能基于上个项目的改进 xff0c 主要是通过对服务器端代码的修改 xff0c 以及对客户端作少许修改 xff0c 实现开启多客户端时 xff0c 一个客户端发送消息 xff0c 达到对所有客户端广播的效果 可参考