效果

实现思路

使用TcpListener建一个服务器,接收所有客户端发送的消息,然后由服务器再发送到其他客户端

客户端使用TcpClient,发消息给服务器,接收服务器的消息,不和其他客户端直接交互

服务器端

接收客户端

开启一个线程,死循环去接收客户端.接收到之后放到一个集合里,保存起来,以便转发消息用.每个客户端都再开启一个线程,用于接收这个客户端发送的消息.

接收客户端的方法AcceptTcpClient()是阻塞方法,在程序退出释放资源时会引发异常,可以先使用Pending()方法先判断是否有挂起的链接请求,有请求的话再去接收.这样可以避免退出时引发的异常.

这里取每隔1秒接收一次.

/// <summary>
/// 接收客户端
/// </summary>
private void AcceptClient()
{
    try
    {
        while (_isAccept)
        {
            if (_listener.Pending())
            {
                TcpClient client = _listener.AcceptTcpClient();
                IPEndPoint endpoint = client.Client.RemoteEndPoint as IPEndPoint;
                _clients.Add(endpoint.ToString(), client);

                //添加到前端客户端列表
                lbx_Clients.Dispatcher.Invoke(() =>
                {
                    lbx_Clients.Items.Add(endpoint.ToString());
                });

                //接收消息线程
                Thread reciveMessageThread = new Thread(ReciveMessage);
                reciveMessageThread.Start(client);
            }
            else
            {
                Thread.Sleep();
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
接收消息并转发

也是死循环接收,使用Read()方法接收.如果远程主机已关闭连接,Read()将立即返回零字节.此时跳出循环,释放资源,结束此线程.

/// <summary>
/// 接收消息
/// </summary>
/// <param name="obj">TcpClient</param>
private void ReciveMessage(object obj)
{
    TcpClient client = obj as TcpClient;
    IPEndPoint endpoint = null;
    NetworkStream stream = null;

    try
    {
        endpoint = client.Client.RemoteEndPoint as IPEndPoint;
        stream = client.GetStream();

        while (true)
        {
            ];
            //如果远程主机已关闭连接,Read将立即返回零字节
            , data.Length);
            )
            {
                #region if
                , length);

                //添加到前端消息列表
                lbx_Messages.Dispatcher.Invoke(() =>
                {
                    lbx_Messages.Items.Add(string.Format("{0}:{1}", endpoint.ToString(), msg));
                });

                //发送到其他客户端
                foreach (KeyValuePair<string, TcpClient> kvp in _clients)
                {
                    if (kvp.Value != client)
                    {
                        string writeMsg = string.Format("{0}:{1}", endpoint.ToString(), msg);
                        byte[] writeData = Encoding.UTF8.GetBytes(writeMsg);
                        NetworkStream writeStream = kvp.Value.GetStream();
                        writeStream.Write(writeData, , writeData.Length);
                    }
                }
                #endregion
            }
            else
            {
                //客户端断开连接 跳出循环
                break;
            }
        }
    }
    catch (Exception ex)
    {
        //Read是阻塞方法 客户端退出是会引发异常 释放资源 结束此线程
    }
    finally
    {
        //从前端客户端列表移除
        lbx_Clients.Dispatcher.Invoke(() =>
        {
            lbx_Clients.Items.Remove(endpoint.ToString());
        });
        //释放资源
        stream.Dispose();
        _clients.Remove(endpoint.ToString());
        client.Dispose();
    }
}

客户端

接收消息

开启线程,死循环接收服务器发送的消息.如果Read()返回0,说明服务器已关闭.

/// <summary>
/// 接收消息
/// </summary>
private void ReciveMessage()
{
    try
    {
        NetworkStream stream = _client.GetStream();
        while (true)
        {
            ];
            , data.Length);
            )
            {
                , length);

                //添加到前端消息列表
                lbx_Messages.Dispatcher.Invoke(() =>
                {
                    lbx_Messages.Items.Add(msg);
                });
            }
            else
            {
                MessageBox.Show("服务器已关闭");
                stream.Dispose();
                break;
            }
        }
    }
    catch (Exception ex)
    {
        //Read是阻塞方法 程序退出释放资源是会引发异常 不做处理 线程结束
    }
}

源码下载:

服务器端:SocketServerDemo.zip

客户端:SocketClientDemo.zip

Socket入门笔记 用TcpClient实现一个简易聊天室的更多相关文章

  1. Python开发【笔记】:aiohttp搭建简易聊天室

    简易聊天室: 1.入口main.py import logging import jinja2 import aiohttp_jinja2 from aiohttp import web from a ...

  2. vue + socket.io实现一个简易聊天室

    vue + vuex + elementUi + socket.io实现一个简易的在线聊天室,提高自己在对vue系列在项目中应用的深度.因为学会一个库或者框架容易,但要结合项目使用一个库或框架就不是那 ...

  3. 真刀实战地搭建React+Webpack+Express搭建一个简易聊天室

    一.前面bb两句 因为自惭(自残)webpack配置还不够熟悉,想折腾着做一个小实例熟悉.想着七夕快到了,做一个聊天室自己和自己聊天吧哈哈.好了,可以停止bb了,说一下干货. 二. 这个项目能学到啥? ...

  4. 原生NodeJs制作一个简易聊天室

    准备工作 安装NodeJs环境 安装编译器Sublime 如果网速不理想,可以百度一下如何加快npm的速度~ 使用node搭建一个简单的网站后台 做完准备工作之后,新建文件夹chatroom,在cha ...

  5. Socket实现简易聊天室,Client,Server

    package seday08; import java.io.BufferedWriter;import java.io.OutputStream;import java.io.OutputStre ...

  6. node+websocket创建简易聊天室

    关于websocket的介绍太多,在这就不一一介绍了,本文主要实现通过websocket创建一个简易聊天室,就是90年代那种聊天室 服务端 1.安装ws模块,uuid模块,ws是websocket模块 ...

  7. node.js+websocket实现简易聊天室

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) websocket提供了一种全双工客户端服务器的异步通信方法,这种通信方法使用ws或者wss协议,可 ...

  8. php_D3_“简易聊天室 ”实现的关键技术 详解

                      PHP+MySQL实现Internet上一个简易聊天室的关键技术  系统目标: 聊天室使用数据库汇集每个人的发言,并可将数据库内的发言信息显示在页面,让每个用户都可 ...

  9. 示例:Socket应用之简易聊天室

    在实际应用中,Server总是在指定的端口上监听是否有Client请求,一旦监听到Client请求,Server就会启动一个线程来响应该请求,而Server本身在启动完线程之后马上又进入监听状态. 示 ...

随机推荐

  1. 移动端web页面开发常用的头部标签设置

    在移动端web页面开发中,我们常需要设置各种头部标签以帮助浏览器更好的解析页面,将页面完美呈现,这里列出了工作中常用的各种头部标签,以备查询. viewport <meta name=" ...

  2. linux 下的ssh

    ssh服务 1.检查是否有被安装,命令 rpm -qa|grep "ssh" 2.检查ssh有没有在运行,命令 rpm -qa|grep "ssh" 3.如何启 ...

  3. 基于 node 搭建博客系统(一)

    系统分为两端,分别实现. 管理员端: 功能 :个人信息,设置,发布随笔,随笔列表,删除随笔,查找,文章 等. 技术点:Boostrap + AdminLTE; 基于nodejs 实现的express ...

  4. 洗礼灵魂,修炼python(31)--面向对象编程(1)—面向对象,对象,类的了解

    面向对象 1.什么是面向对象 (图片来自网络) 哈哈,当然不是图中的意思. 1).面向对象(Object Oriented,OO)是软件开发方法.利用各大搜索引擎得到的解释都太官方,完全看不懂啥意思对 ...

  5. SQL Server 临时表和表变量系列之选择篇

    原文地址:https://yq.aliyun.com/articles/69187 摘要: # 摘要 通过前面的三篇系列文章,我们对临时表和表变量的概念.对比和认知误区已经有了非常全面的认识.其实,我 ...

  6. scrapy爬取校花网男神图片保存到本地

    爬虫四部曲,本人按自己的步骤来写,可能有很多漏洞,望各位大神指点指点 1.创建项目 scrapy startproject xiaohuawang scrapy.cfg: 项目的配置文件xiaohua ...

  7. STL set简单用法

    set的常见用法详解 set翻译为集合,是一个内部自动有序并且不含重复元素的容器. 可以用于去掉重复元素,或者元素过大,或者不能散列的情况,set只保留元素本身而不考虑它的个数. 头文件:#inclu ...

  8. Instruments模板介绍(更新中...)

    第一章.Instruments(仪器)快速入门 Instruments可以用来收集关于一个或者多个系统进程的性能和行为的数据,并跟踪睡着时间产生的数据.它提供了好几个分析模板: Blank 任何类型都 ...

  9. svn 更新

    dev更新流程: 1.打开软件,文件—>打开,弹出右边对话框链接dev地址      2.在窗口输入cd /var/www/user 回车 3.输入svn up 则更新dev代码完成 本地提交到 ...

  10. 网络编程_UDP协议_发送端与接收端

    创建UDP传输的发送端 : 1.建立udp的socket服务   2.将要发送的数据封装到数据包中   3.通过udp的socket服务 将数据包发送出去   4.关闭socket服务(因为调用了系统 ...