c#网编实验五--WCF和TCP消息通信实验

news2024/11/15 23:22:09

分别编写服务端和客户端程序,利用基于WCF的TCP技术,实现在线聊天功能,完成在线用户列表管理,消息发送、接收的功能。

在同一个解决方案中,分别编写服务端程序和客户端程序,利用TCP实现简单的群聊功能。

 

 

具体要求如下:
(1)服务端程序选择【WCF服务库】模板,客户端程序选择【WPF应用程序】模板。
(2)客户端与服务端连接成功后,通过服务端获取已经在线的用户,并将其显示在客户端的在线用户列表中。
(3)不论哪个用户发送聊天消息,其他所有用户都能看到该消息。
(4)当某个用户退出后,在线用户列表中自动移除该用户。
 

重点:

(1)掌握TCP协议下WCF服务应用程序构建方法。
(2)掌握客户端和服务端通信接口设计方法。
(3)掌握协定的设计及实现方法。
(4)掌握双工通信的设计及实现方法。
(5)熟悉WCF和TCP的相关绑定设置。
难点:

(1)掌握客户端和服务端通信接口设计方法。
(2)掌握协定的设计及实现方法。
(3)掌握双工通信的设计及实现方法。
(4)熟悉WCF和TCP的相关绑定设置。
 

客户端

MainWindow.xaml

<Window x:Class="ChatClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="主界面" Height="350" Width="525" WindowStartupLocation="CenterScreen">
    <StackPanel VerticalAlignment="Center">
        <Button Name="btn1" Margin="10" Width="170" Content="同时启动2个客户端(测试用)" Click="btn1_Click"/>
        <Button Name="btn2" Margin="10" Width="170" Content="只启动1个客户端(实际情况)" Click="btn2_Click"/>
    </StackPanel>
</Window>

 

 

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ChatClient
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            StartWindow("西西皮", 50, 300);
            StartWindow("瓜瓜糖", 600, 300);
        }

        private void StartWindow(string userName, int left, int top)
        {
            ClientWindow w = new ClientWindow();
            w.Left = left;
            w.Top = top;
            w.UserName = userName;
            w.Owner = this;
            w.Closed += (sender, e) => this.Activate();
            w.Show();
        }

        private void btn2_Click(object sender, RoutedEventArgs e)
        {
            ClientWindow w = new ClientWindow();
            w.Owner = this;
            w.Closed += (sendObj, args) => this.Activate();
            w.Show();
        }
    }
}

ClientWindow.xaml

<Window x:Class="ChatClient.ClientWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="群聊客户端" Height="300" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0" Background="Cornsilk" LastChildFill="False">
            <TextBlock Text="用户名:" DockPanel.Dock="Left" VerticalAlignment="Center"/>
            <TextBox Name="textBoxUserName" Text="西西" Width="100" VerticalAlignment="Center"/>
            <Button Name="btnLogin" Content="登录" Click="btnLogin_Click" DockPanel.Dock="Left" Padding="10 0 10 0" Margin="5"/>
        </DockPanel>
        <DockPanel Name="dockPanel1" Grid.Row="1">
            <Grid Width="60">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <TextBlock Text="在线用户" Grid.Row="0" Background="Blue" Foreground="White" TextAlignment="Center"/>
                <Grid Grid.Row="1">
                    <ListBox Name="listBoxOnLine" Background="AntiqueWhite"/>
                </Grid>
            </Grid>
            <Grid Grid.Row="1">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <TextBlock Name="textBlockMessage" Grid.Row="0"
                 Text="对话信息" Background="Beige" TextAlignment="Center"/>
                <ListBox Name="listBoxMessage" Grid.Row="1" BorderThickness="1" Padding="0 5 0 0"/>
                <DockPanel Grid.Row="2">
                    <TextBlock Text="发言:" Margin="10 0 0 0" DockPanel.Dock="Left" VerticalAlignment="Center"/>
                    <Button Name="btnSend" Click="btnSend_Click" Content="发送" Width="50" DockPanel.Dock="Right" Margin="10 0 10 0"/>
                    <TextBox Name="textBoxTalk" KeyDown="textBoxTalk_KeyDown"/>
                </DockPanel>
            </Grid>
        </DockPanel>
    </Grid>
</Window>

 

 

ClientWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ChatClient.ChatServiceReference;

namespace ChatClient
{
    /// <summary>
    /// ClientWindow.xaml 的交互逻辑
    /// </summary>
    public partial class ClientWindow : Window, IChatServiceCallback
    {
        public ClientWindow()
        {
            InitializeComponent();
            this.Closing += ClientWindow_Closing;
            dockPanel1.Visibility = System.Windows.Visibility.Hidden;
        }

        public string UserName
        {
            get { return textBoxUserName.Text; }
            set { textBoxUserName.Text = value; }
        }
        private ChatServiceClient client;

        void ClientWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (client != null)
            {
                client.Logout(UserName); //退出
                client.Close();
            }
        }

        private void AddMessage(string str)
        {
            TextBlock t = new TextBlock();
            t.Text = str;
            t.Foreground = Brushes.Blue;
            listBoxMessage.Items.Add(t);
        }

        //单击登录按钮引发的事件
        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            this.Cursor = Cursors.Wait;
            UserName = textBoxUserName.Text;
            InstanceContext context = new InstanceContext(this);
            client = new ChatServiceReference.ChatServiceClient(context);
            try
            {
                client.Login(textBoxUserName.Text);
                btnLogin.IsEnabled = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show("与服务端连接失败:" + ex.Message);
                return;
            }
            this.Cursor = Cursors.Arrow;
        }

        //单击发送按钮引发的事件
        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            client.Talk(UserName, textBoxTalk.Text);
            textBoxTalk.Text = "";
        }

        //在文本框中输入对话后按回车键时引发的事件
        private void textBoxTalk_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                client.Talk(UserName, textBoxTalk.Text);
                textBoxTalk.Text = "";
            }
        }

        #region 实现IRndGameServiceCallback接口
        /// <summary>有用户登录</summary>
        public void ShowLogin(string loginUserName)
        {
            if (loginUserName == UserName)
            {
                dockPanel1.Visibility = System.Windows.Visibility.Visible;
            }
            listBoxOnLine.Items.Add(loginUserName);
        }

        /// <summary>其他用户退出</summary>
        public void ShowLogout(string userName)
        {
            listBoxOnLine.Items.Remove(userName);
        }

        public void ShowTalk(string userName, string message)
        {
            AddMessage(string.Format("[{0}]说:{1}", userName, message));
        }

        public void InitUsersInfo(string UsersInfo)
        {
            if (UsersInfo.Length == 0) return;
            string[] users=UsersInfo.Split('、');
            for (int i = 0; i < users.Length; i++)
            {
                listBoxOnLine.Items.Add(users[i]);
            }
        }
        #endregion
    }
}

服务端

IChatService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace ChatServer
{
    //需要服务端实现的协定
    [ServiceContract(Namespace = "WcfChatExample", CallbackContract = typeof(IChatServiceCallback))]
    public interface IChatService
    {
        [OperationContract(IsOneWay = true)]
        void Login(string userName);

        [OperationContract(IsOneWay = true)]
        void Logout(string userName);

        [OperationContract(IsOneWay = true)]
        void Talk(string userName, string message);
    }

    //需要客户端实现的接口
    public interface IChatServiceCallback
    {
        [OperationContract(IsOneWay = true)]
        void ShowLogin(string loginUserName);

        [OperationContract(IsOneWay = true)]
        void ShowLogout(string userName);

        [OperationContract(IsOneWay = true)]
        void ShowTalk(string userName, string message);

        [OperationContract(IsOneWay = true)]
        void InitUsersInfo(string UsersInfo);
    }
}

 

 

 ChatService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace ChatServer
{
    public class ChatService : IChatService
    {
        /// <summary>
        /// 用户退出。参数:登录者用户名
        /// </summary>
        public void Login(string userName)
        {
            OperationContext context = OperationContext.Current;
            IChatServiceCallback callback = context.GetCallbackChannel<IChatServiceCallback>();
            User newUser = new User(userName, callback);
            string str = "";
            for (int i = 0; i < CC.Users.Count; i++)
            {
               str += CC.Users[i].UserName + "、";
            }
            newUser.callback.InitUsersInfo(str.TrimEnd('、'));
            CC.Users.Add(newUser);
            foreach (var user in CC.Users)
            {
                user.callback.ShowLogin(userName);
            }
        }

        /// <summary>
        /// 用户退出。参数:退出者用户名
        /// </summary>
        public void Logout(string userName)
        {
            User logoutUser = CC.GetUser(userName);
            CC.Users.Remove(logoutUser);
            logoutUser = null; //将其设置为null后,WCF会自动关闭该客户端
            foreach (var user in CC.Users)
            {
                user.callback.ShowLogout(userName);
            }
        }

        /// <summary>
        /// 客户端发来的对话信息。参数:发送者用户名,对话内容
        /// </summary>
        public void Talk(string userName, string message)
        {
            User user = CC.GetUser(userName);
            foreach (var v in CC.Users)
            {
                v.callback.ShowTalk(userName, message);
            }
        }
    }
}

User.cs

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

namespace ChatServer
{
    public class User
    {
        public string UserName { get; set; }
        public readonly IChatServiceCallback callback;

        public User(string userName, IChatServiceCallback callback)
        {
            this.UserName = userName;
            this.callback = callback;
        }
    }
}

 

CC.cs

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

namespace ChatServer
{
    public class CC
    {
        //连接的用户,每个用户都对应一个ChatService线程
        public static List<User> Users { get; set; }

        static CC()
        {
            Users = new List<User>();
        }

        public static User GetUser(string userName)
        {
            User user = null;
            foreach (var v in Users)
            {
                if (v.UserName == userName)
                {
                    user = v;
                    break;
                }
            }
            return user;
        }
    }
}

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

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

相关文章

【领域驱动设计专题】一文带领你透视DDD领域驱动模型的本质和设计原理分析指南(构建领域知识)

一文带领你透视DDD领域驱动模型的本质和设计原理分析指南 前提介绍传统的软件设计方案瀑布设计方法敏捷方法学敏捷方法学的问题和局限性 构建领域知识认识和了解领域内容实体模型介绍分析飞行计划路线(route)路线(route) 领域专家进行交流&#xff0c;相互交换知识挖掘出关键的…

一台服务器最大能支持多少条 TCP 连接

一、一台服务器最大能打开的文件数 1、限制参数 我们知道在Linux中一切皆文件&#xff0c;那么一台服务器最大能打开多少个文件呢&#xff1f;Linux上能打开的最大文件数量受三个参数影响&#xff0c;分别是&#xff1a; fs.file-max &#xff08;系统级别参数&#xff09;&a…

npm发布自己的包

按照上面流程操作

基于Echarts构建停车场数据可视化大屏

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

XSS—存储型xss

xss >跨站脚本攻击>前端代码注入>用户输入的数据会被当做前端代码执行。 原理&#xff1a;使用者提交的XSS代码被存储到服务器上的数据库里或页面或某个上传文件里&#xff0c;导致用户访问页面展示的内容时直接触发xss代码。 输入内容后直接在下方回显&#xff0c;回…

【Python 随练】今天是哪一天?

题目&#xff1a; 输入某年某月某日&#xff0c;判断这一天是这一年的第几天&#xff1f; 简介&#xff1a; 在本篇博客中&#xff0c;我们将使用Python代码解决一个日期相关的问题&#xff1a;如何确定某一天是给定年份的第几天。我们将提供问题的解析&#xff0c;并给出一…

领导看了给你加薪!python +ddt+excel 一招鲜,接口自动化测试轻松搞定,测试报告惊艳四座!

“ 接口自动化测试是指通过编写代码或使用工具&#xff0c;模拟用户发送请求&#xff0c;验证接口是否符合设计规范和功能需求的过程。” 如何用 python ddtexcel 实现接口自动化测试 接口自动化测试可以提高测试效率和质量&#xff0c;节省测试成本和时间&#xff0c;保证测试…

使用PyTorch执行特征提取和微调的迁移学习来进行图像分类

使用PyTorch执行特征提取和微调的迁移学习来进行图像分类 1. 效果图2 项目结构3 什么是迁移学习4 如何使用PyTorch进行迁移学习&#xff1f;5 花朵数据集源码train_feature_extraction.pyfine_tune.pyinference.py 参考 这篇博客将介绍如何使用PyTorch深度学习库执行图像分类的…

U盘重装系统Win10详细步骤和方法

当前超多的用户都在使用Win10系统&#xff0c;有些用户想使用U盘来重装一下Win10系统&#xff0c;但不知道具体怎么操作&#xff0c;其实操作起来难度不会很大&#xff0c;可以按照以下小编给大家分享的U盘重装系统Win10详细步骤和方法&#xff0c;就能轻松顺利完成U盘重装系统…

Jetson TX2 NX的GPIO引脚使用方式

Jetson TX2 NX是一款高性能的嵌入式AI计算平台&#xff0c;其中引脚的设计和使用对于开发人员来说非常重要。在本文中&#xff0c;我们将会介绍Jetson TX2 NX的引脚并说明其功能和使用方式。 官方文档官方文档 引脚概述 Jetson TX2 NX具有许多不同类型的引脚&#xff0c;包…

C++ 类的构造函数和析构函数

目录 类的构造函数和析构函数构造函数声明构造函数定义构造函数使用构造函数默认构造函数 析构函数析构函数的声明析构函数的定义 改进Stock类(加入构造函数和析构函数) 类的构造函数和析构函数 构造函数 常规的初始化语法不适用类的初始化 例如&#xff1a; int a 10;//整…

Deepin20.9 安装Mysql

文章目录 mysql下载查看 mysql 状态卸载卸载mysql&#xff1a;清理残留数据检查是否删除完毕 mysql Deepin 安装 下载 从网上下载 https://dev.mysql.com/get/mysql-apt-config_0.8.23-1_all.deb 安装 mysql-apt-config 下载文件名: mysql-apt-config_0.8.23-1_all.deb …

PoseiSwap IDO 即将开启,一览 $POSE 经济模型

以太坊创始人 Vitalik Buterin 曾在今年以太坊黑山大会上&#xff0c;进行了以“以太坊的三个技术挑战&#xff1a;扩容、隐私和用户安全”为主题的演讲&#xff0c;阐明了具有隐私性、可扩展性和安全性的且易访问的区块链生态将是行业发展趋势&#xff0c;或许重复造轮子正在变…

【探索 Kubernetes|作业管理篇 系列 10】Pod 健康检查和恢复机制

前言 大家好&#xff0c;我是秋意零。 上一篇中介绍了&#xff0c;Pod 的服务对象&#xff0c;从而对 Pod 有了更深的理解&#xff1b; 今天的主题是 Pod 健康检查和恢复机制&#xff0c;我们将结束 Pod 的内容。 最近搞了一个扣扣群&#xff0c;旨在技术交流、博客互助&am…

图像中提取文本

将从此图像中提取文本。我使用得是 PyCharm&#xff0c;您随意编辑器或IDE 1、下载所需得库和exe文件&#xff1a; tesseract-ocr 可执行exe文件下载后&#xff0c;安装时无需指定安装目录。 http://jaist.dl.sourceforge.net/project/tesseract-ocr-alt/tesseract-ocr-setup-3…

代码随想录二刷day25 | 回溯 之 216.组合总和III 17.电话号码的字母组合

216.组合总和III 题目链接 解题思路&#xff1a; 选取过程如图&#xff1a; 图中&#xff0c;可以看出&#xff0c;只有最后取到集合&#xff08;1&#xff0c;3&#xff09;和为4 符合条件。 递归三部曲 确定递归函数参数 和77. 组合 一样&#xff0c;依然需要一维数组path…

走进人工智能|深度学习 算法的创世纪

前言&#xff1a; 深度学习通过训练深层神经网络模型&#xff0c;可以自动学习和提取数据的特征&#xff0c;包括更准确的图像识别、自然语言处理、医学诊断等方面的应用。 文章目录 序言背景算法的创世纪技术支持应用领域程序员如何学总结 序言 深度学习是一种机器学习方法&a…

easyui05(datagrid数据新增)

一.对话框&#xff1a;Dialog 加载页面 <div id"myDialog" style"display:none"></div> 二.editGoods.jsp 表单 myForm <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <tit…

2023年互联网Java面试复习大纲:ZK+Redis+MySQL+Java基础+架构

多数的公司总体上面试都是以自我介绍项目介绍项目细节/难点提问基础知识点考核算法题这个流程下来的。有些公司可能还会问几个实际的场景类的问题&#xff0c;这个环节阿里是必问的&#xff0c;这种问题通常是没有正确答案的&#xff0c;就看个人的理解&#xff0c;个人的积累了…

Vue练手项目之仿京东到家主页

目录 概述1.效果展示2.使用原始HtmlCSS实现3.使用Vue.js进行组件化3.1 Header部分组件实现3.1.1图标的展示3.1.2 定义Vue调试的名称3.1.3 使用scoped隔离组件间的css影响 3.2 附近店铺部分实现3.3 底部导航栏组件的实现3.4 将组件组成一个整体页面 4.代码地址 概述 本人是一个…