博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天、消息模块
阅读量:4489 次
发布时间:2019-06-08

本文共 30235 字,大约阅读时间需要 100 分钟。

原文:

中秋节假期没事继续搞了搞

做了各聊天的模块,需要继续优化

第一步画页面

页面参考仿微信的页面

加了截图发送图片

效果这样,点击右下角图标显示,可以拖动位置、隐藏、最大化(请忽略工具条里的颜色选择器,做的颜色选择器在这里试试,没啥意义)

截图大概这样

发送消息

截图代码也是网上找的,做了些改动,不记得是哪里了,有需要的可以找我要,这里就不贴了

页面画好了下面就要些服务端了

第二步 socket服务

写的比较简单

直接贴代码把,这个自己写的随便拿去用

程序入口

Program.cs

using System;using System.Collections;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Web.Script.Serialization;using System.Windows.Forms;namespace PW.SocketServer{    static class Program    {        static MyServer myServer = null;        ///         /// 应用程序的主入口点。        ///         [STAThread]        static void Main()        {            //Application.EnableVisualStyles();            //Application.SetCompatibleTextRenderingDefault(false);            myServer = MyServer.GetInstance();            //myServer.ReceivedMsg = new MyServer.ReceivedMsgHandler(socketClient_ReceivedMsg);                       //Application.Run(new FormMain());                       FormMain main = null;            new Thread((ThreadStart)delegate            {                main = new FormMain();                Application.Run(main);            }).Start();            myServer.BeginServer();            Console.ReadLine();        }    }}

在启动服务的时候,同时启动的一个窗口,用来测试的

MyServer.cs

using System;using System.Collections;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Windows.Forms;namespace PW.SocketServer{        public class MyServer    {        Thread threadWatch = null;// 负责监听客户端的线程        Socket socketWatch = null;// 负责监听客户端的套接字        Dictionary
clientList = null; Int32 con_msg_length = 10240; private static MyServer uniqueInstance; public delegate void ReceivedMsgHandler(string msg); public ReceivedMsgHandler ReceivedMsg;//自定义事件 public delegate void ClientChangeHandler(ClientUser client, Dictionary
clientList); public ClientChangeHandler ClientAdd;//自定义事件 public ClientChangeHandler ClientRemove;//自定义事件 ///
/// 获取单例 /// ///
public static MyServer GetInstance() { // 如果类的实例不存在则创建,否则直接返回 if (uniqueInstance == null) { uniqueInstance = new MyServer(); } return uniqueInstance; } private MyServer() { try { string ServerIP = System.Configuration.ConfigurationManager.AppSettings["ServerIP"].ToString(); string ServerPort = System.Configuration.ConfigurationManager.AppSettings["ServerPort"].ToString(); con_msg_length = Int32.Parse(System.Configuration.ConfigurationManager.AppSettings["MsgLength"].ToString()); IPAddress ip = null; if (string.IsNullOrEmpty(ServerIP)) { ip = IPAddress.Any;//创建IP//Any 字段等效于以点分隔的四部分表示法格式的 0.0.0.0 这个IP地址,实际是一个广播地址。//对于SOCKET而言,使用 any ,表示,侦听本机的所有IP地址的对应的端口(本机可能有多个IP或只有一个IP) } else { ip = IPAddress.Parse(ServerIP);//监听指定ip } IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(ServerPort));//创建终结点(EndPoint) clientList = new Dictionary
(); // 定义一个套接字用于监听客户端发来的消息,包含三个参数(ipv4寻址协议,流式连接,tcp协议) socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 监听绑定的网路节点 socketWatch.Bind(point); // 将套接字的监听队列长度设置限制为0,0表示无限 socketWatch.Listen(0); // 创建一个监听线程 threadWatch = new Thread(WatchConnecting); threadWatch.IsBackground = true; } catch (Exception ex) { WriteTxtLog(ex.Message); } } public void BeginServer() { try { threadWatch.Start(); AppendText("成功启动监听!"); } catch (Exception ex) { WriteTxtLog(ex.Message); } } ///
/// 监听客户端发来的请求 /// private void WatchConnecting() { //持续不断监听客户端发来的请求 while (true) { try { Socket clientSocket = socketWatch.Accept(); byte[] recMsg = new byte[con_msg_length]; if (clientSocket != null && clientSocket.Connected) { int length = clientSocket.Receive(recMsg); string msg = ""; if (length > 0) { //将机器接受到的字节数组转换为人可以读懂的字符串 msg = Encoding.UTF8.GetString(recMsg, 0, length); } AppendText("==[" + msg + "]==" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\r\n"); SocketMsg smsg = new SocketMsg(); try { smsg.setAllParametersJsonStr(msg); } catch { } Hashtable param = smsg.getAllParameters(); ClientUser cu = new ClientUser(); cu.ClientSocket = clientSocket; IPEndPoint ip = (IPEndPoint)clientSocket.RemoteEndPoint; cu.CliIp = ip.Address.ToString(); cu.CliPort = ip.Port.ToString(); cu.LoginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); AppendText("客户端连接!" + cu.CliIp + ":" + cu.CliPort + "\r\n"); string userno = ""; if (param != null && param.Count > 0) { userno = param["UserNo"].ToString(); cu.UserNo = userno; cu.UserName = param["UserName"].ToString(); } if (!clientList.ContainsKey(userno)) { clientList.Add(userno, cu); if (ClientAdd != null) { ClientAdd(cu, clientList); } } else { if (ClientRemove != null) { ClientRemove(clientList[userno], clientList); } clientList.Remove(userno); clientList.Add(userno, cu); if (ClientAdd != null) { ClientAdd(cu, clientList); } } AppendText("客户端连接成功!" + msg + "\r\n"); // 创建一个通信线程 ParameterizedThreadStart pts = new ParameterizedThreadStart(acceptMsg); Thread thr = new Thread(pts); thr.IsBackground = true; thr.Start(clientSocket); } } catch (Exception ex) { WriteTxtLog(ex.Message); } } } ///
/// 接收客户端发来的消息 /// ///
客户端套接字对象 private void acceptMsg(object socket) { Socket socketServer = socket as Socket; while (true) { try { //创建一个内存缓冲区 其大小为1024*1024字节 即1M byte[] recMsg = new byte[con_msg_length]; //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度 int length = socketServer.Receive(recMsg); //将机器接受到的字节数组转换为人可以读懂的字符串 if (length > 0) { try { string msg = Encoding.UTF8.GetString(recMsg, 0, length); AppendText("==[" + msg + "]==" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\r\n"); SocketMsg smsg = new SocketMsg(); try { smsg.setAllParametersJsonStr(msg); } catch { } Hashtable param = smsg.getAllParameters(); if (param != null && param.Count > 0) { AppendText("客户端(" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "):" + smsg.ConvertJson2Str(param["msgContent"]) + "\r\n"); string usernos = param["UserNo"] == null ? "" : param["UserNo"].ToString(); string[] nos = usernos.Split(','); if (nos != null && nos.Length > 0) { //转发消息到目标客户端 foreach (string no in nos) { if (clientList.ContainsKey(no) && clientList[no].ClientSocket != socketServer) { serverSendMsg(clientList[no].ClientSocket, smsg.ConvertJson2Str(param["msgContent"])); } } } } } catch (Exception exx) { AppendText("" + exx.Message + "(" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "):\r\n"); } } else { string clin = ""; foreach (string key in clientList.Keys) { if (clientList[key].ClientSocket == socketServer) { clin = "userno:" + clientList[key].UserNo + " name:" + clientList[key].UserName + " ip:" + clientList[key].CliIp; if (ClientRemove != null) { ClientRemove(clientList[key], clientList); } clientList.Remove(key); break; } } AppendText("客户端[" + clin + "]断开(" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "):\r\n"); socketServer.Disconnect(true); socketServer.Close(); break; } } catch (Exception ex) { string clin = ""; foreach (string key in clientList.Keys) { if (clientList[key].ClientSocket == socketServer) { clin = "userno:" + clientList[key].UserNo + " name:" + clientList[key].UserName + " ip:" + clientList[key].CliIp; if (ClientRemove != null) { ClientRemove(clientList[key], clientList); } clientList.Remove(key); break; } } AppendText("客户端[" + clin + "]断开(" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "):\r\n"); socketServer.Disconnect(true); socketServer.Close(); break; } } } ///
/// 发送消息到客户端 /// ///
public void serverSendMsg(Socket clientSocket, string msg) { try { byte[] sendMsg = Encoding.UTF8.GetBytes(msg); clientSocket.Send(sendMsg); AppendText("服务端(" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "):" + msg + "\r\n"); } catch (Exception ex) { WriteTxtLog(ex.Message); } } private void AppendText(String theContent) { Console.WriteLine(theContent); WriteTxtLog(theContent); } private void WriteTxtLog(String theContent) { try { String theFileName = DateTime.Now.ToString("yyyyMMdd") + ".txt"; String theFilePath = Application.StartupPath + "\\MsgLog\\"; String theFullName = theFilePath + theFileName; //判断文件夹是否存在 if (Directory.Exists(theFilePath) == false)//如果不存在就创建file文件夹 { Directory.CreateDirectory(theFilePath); } StreamWriter sw = null; //判断文件是否存在 if (File.Exists(theFullName)) { sw = File.AppendText(theFullName); } else { sw = File.CreateText(theFullName);//创建该文件 } //导出传盘文件 //开始写入 sw.WriteLine(theContent); //关闭流 sw.Close(); } catch (Exception ex) { } } public Dictionary
getClient() { return clientList; } }}

SocketMsg.cs

using System;using System.Collections.Generic;using System.Collections;using System.Linq;using System.Text;using System.Web.Script.Serialization;namespace PW.SocketServer{    public class SocketMsg    {        ///         /// 请求的参数        ///         protected Hashtable parameters;        ///         /// 获取参数值        ///         /// 参数名        /// 
public string getParameter(string parameter) { string s = (string)parameters[parameter]; return (null == s) ? "" : s; } /// /// 设置参数值 /// /// 参数名 /// 参数值 public void setParameter(string parameter, string parameterValue) { if (parameter != null && parameter != "") { if (parameters.Contains(parameter)) { parameters.Remove(parameter); } parameters.Add(parameter, parameterValue); } } /// /// 获取所有参数 /// ///
public Hashtable getAllParameters() { return this.parameters; } /// /// 获取所有参数Json /// ///
public String getAllParametersJsonStr() { JavaScriptSerializer jsser = new JavaScriptSerializer(); String jsonStr = jsser.Serialize(this.parameters); return jsonStr; } /// /// 获取所有参数Json /// ///
public void setAllParametersJsonStr(String jsonStr) { JavaScriptSerializer jsser = new JavaScriptSerializer(); parameters = jsser.Deserialize
(jsonStr); } ///
/// /// ///
public String ConvertJson2Str(object json) { try { JavaScriptSerializer jsser = new JavaScriptSerializer(); String jsonStr = jsser.Serialize(json); return jsonStr; } catch { return json.ToString(); } } }}

ClientUser.cs

using System;using System.Collections.Generic;using System.Linq;using System.Net.Sockets;using System.Text;using System.Threading.Tasks;namespace PW.SocketServer{    public class ClientUser    {        public string UserNo { get; set; }        public string UserName { get; set; }        public string LoginTime { get; set; }        public string CliIp { get; set; }        public string CliPort { get; set; }        public Socket ClientSocket { get; set; }    }}

不太会贴form代码

来个截图,就是来显示一下在线人员,和像指定的人发个消息,myserver,那里留的有口儿,这里只是用

cs代码

FormMain.cs

using System;using System.Collections.Generic;using System.Linq;using System.Windows.Forms;using System.IO;namespace PW.SocketServer{    public partial class FormMain : Form    {        MyServer myServer = null;              public FormMain()        {            myServer = MyServer.GetInstance();            myServer.ClientAdd = new MyServer.ClientChangeHandler(myServer_ClientAdd);            myServer.ClientRemove = new MyServer.ClientChangeHandler(myServer_ClientRemove);            InitializeComponent();            //关闭对文本框的非法线程操作检查            TextBox.CheckForIllegalCrossThreadCalls = false;            DataGridView.CheckForIllegalCrossThreadCalls = false;        }        void myServer_ClientAdd(ClientUser client, Dictionary
clientList) { LoadGrid(); } void myServer_ClientRemove(ClientUser client, Dictionary
clientList) { LoadGrid(); } private void FormMain_Load(object sender, EventArgs e) { } private void LoadGrid() { try { dataGridView1.Rows.Clear(); Dictionary
tmps = myServer.getClient(); foreach (ClientUser cu in tmps.Values) { dataGridView1.Rows.Add(1); dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells["UserNo"].Value = cu.UserNo; dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells["UserName"].Value = cu.UserName; dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells["CliIp"].Value = cu.CliIp; dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells["CliPort"].Value = cu.CliPort; dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells["LoginTime"].Value = cu.LoginTime; } } catch (Exception ex) { } } private void button1_Click(object sender, EventArgs e) { if(dataGridView1.SelectedRows.Count>0) { string msg = "{title:'" + txtTitle.Text + "',content:'" + txtContent.Text + "'}"; Dictionary
tmps = myServer.getClient(); try { foreach (DataGridViewRow row in dataGridView1.SelectedRows) { if (tmps.ContainsKey(row.Cells["UserNo"].Value.ToString())) { myServer.serverSendMsg(tmps[row.Cells["UserNo"].Value.ToString()].ClientSocket, msg); } } } catch { foreach (DataGridViewRow row in dataGridView1.SelectedRows) { var query = tmps.SingleOrDefault(p => p.Value.CliIp == row.Cells["CliIp"].Value.ToString()); if (query.Value != null) { myServer.serverSendMsg(query.Value.ClientSocket, msg); } } } } } private void AppendText(String theContent) { Console.WriteLine(theContent); WriteTxtLog(theContent); } private void WriteTxtLog(String theContent) { try { String theFileName = DateTime.Now.ToString("yyyyMMdd") + ".txt"; String theFilePath = Application.StartupPath + "\\MsgLog\\"; String theFullName = theFilePath + theFileName; //判断文件夹是否存在 if (Directory.Exists(theFilePath) == false)//如果不存在就创建file文件夹 { Directory.CreateDirectory(theFilePath); } StreamWriter sw = null; //判断文件是否存在 if (File.Exists(theFullName)) { sw = File.AppendText(theFullName); } else { sw = File.CreateText(theFullName);//创建该文件 } //导出传盘文件 //开始写入 sw.WriteLine(theContent); //关闭流 sw.Close(); } catch (Exception ex) { } } }}

配置文件--比较简单

 

到这里一个简单的socket已经写好了,写的比较i简单,可能不太稳定,本来想用之前用java写的那套服务呢,想想最后还是用C#写了

 

第三步 连通前后台 

主要就是一个类

SocketClient.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net.Sockets;using System.Threading;using System.Net;namespace PW.Infrastructure{    public class SocketClient    {        private static SocketClient uniqueInstance;        // 创建一个客户端套接字        Socket clientSocket = null;        // 创建一个监听服务端的线程        Thread threadServer = null;        string start_msg = "";        public delegate void ReceivedMsgHandler(string msg);        public ReceivedMsgHandler ReceivedMsg;//自定义事件        private SocketClient()        {            try            {                start_msg = "{UserNo:'" + GlobalData.UserName + "',UserName:'" + GlobalData.NickName + "'}";            }            catch(Exception ex)            {                WriteTxtLog(ex.Message);            }        }        ///         /// 获取单例        ///         /// 
public static SocketClient GetInstance() { // 如果类的实例不存在则创建,否则直接返回 if (uniqueInstance == null) { uniqueInstance = new SocketClient(); } return uniqueInstance; } public void BeginConnect() { try { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(GlobalData.SocketIP); clientSocket.BeginConnect(ip, GlobalData.SocketPort, (args) => { if (args.IsCompleted) //判断该异步操作是否执行完毕 { Byte[] bytesSend = new Byte[GlobalData.SocketMsgSize]; bytesSend = Encoding.UTF8.GetBytes(start_msg); //用户名,这里是刚刚连接上时需要传过去 if (clientSocket != null && clientSocket.Connected) { clientSocket.Send(bytesSend); WriteTxtLog("链接成功(" + GetCurrentTime() + "):\r\n"); // 创建一个线程监听服务端发来的消息 threadServer = new Thread(recMsg); threadServer.IsBackground = true; threadServer.Start(); } else { WriteTxtLog("服务器未开启(" + GetCurrentTime() + "):\r\n"); // 创建一个线程监听服务端发来的消息 threadServer = new Thread(recMsg); threadServer.IsBackground = true; threadServer.Start(); } } }, null); } catch (Exception ex) { WriteTxtLog(ex.Message); } } /// /// 接收服务端发来的消息 /// private void recMsg() { while (true) //持续监听服务端发来的消息 { //定义一个1M的内存缓冲区 用于临时性存储接收到的信息 byte[] arrRecMsg = new byte[GlobalData.SocketMsgSize]; int length = 0; try { //将客户端套接字接收到的数据存入内存缓冲区, 并获取其长度 length = clientSocket.Receive(arrRecMsg); //将套接字获取到的字节数组转换为人可以看懂的字符串 string strRecMsg = Encoding.UTF8.GetString(arrRecMsg, 0, length); if (ReceivedMsg != null) { ReceivedMsg(strRecMsg); } //将发送的信息追加到聊天内容文本框中 WriteTxtLog("服务端(" + GetCurrentTime() + "):" + strRecMsg + "\r\n"); } catch(Exception ex) { WriteTxtLog("" + ex.Message+ ":\r\n"); WriteTxtLog("服务器已关闭(" + GetCurrentTime() + "):\r\n"); //重连 Thread.Sleep(10 * 1000); if (!clientSocket.Connected) { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.BeginConnect(IPAddress.Parse(GlobalData.SocketIP), GlobalData.SocketPort, (args) => { if (args.IsCompleted) //判断该异步操作是否执行完毕 { Byte[] bytesSend = new Byte[GlobalData.SocketMsgSize]; bytesSend = Encoding.UTF8.GetBytes(start_msg); //用户名,这里是刚刚连接上时需要传过去 if (clientSocket != null && clientSocket.Connected) { clientSocket.Send(bytesSend); WriteTxtLog("重连链接成功(" + GetCurrentTime() + "):\r\n"); } else { WriteTxtLog("重连失败服务器已关闭(" + GetCurrentTime() + "):\r\n"); } } }, null); } } } } /// /// 发送消息到服务端 /// /// public void SendMsg(string title, string content, string userno) { try { string msg = "{title:'" + title + "',content:'" + content + "'}"; //userno:"001,002,003" if (string.IsNullOrEmpty(userno)) { userno = "0"; } string msgcon = "{msgType:'msg',msgContent:'" + msg + "',UserNo:'" + userno + "'}"; clientSendMsg(msgcon); } catch (Exception ex) { WriteTxtLog(ex.Message); } } public void CloseConnect() { try { if (clientSocket != null) clientSocket.Close(); if (threadServer != null && threadServer.IsAlive) { threadServer.Abort(); } clientSocket = null; threadServer = null; } catch (Exception ex) { WriteTxtLog(ex.Message); } } /// /// 发送消息到服务端 /// /// public void clientSendMsg(string msg) { byte[] sendMsg = Encoding.UTF8.GetBytes(msg); clientSocket.Send(sendMsg); WriteTxtLog("客户端(" + GetCurrentTime() + "):" + msg + "\r\n"); } /// /// 获取当前系统时间的方法 /// ///
当前时间
private DateTime GetCurrentTime() { DateTime currentTime = new DateTime(); currentTime = DateTime.Now; return currentTime; } public static void WriteTxtLog(String theContent) { try { //String theFileName = DateTime.Now.ToString("yyyyMMdd") + ".txt"; //String theFilePath = Application.StartupPath +"\\MsgLog\\"; //String theFullName = theFilePath + theFileName; 判断文件夹是否存在 //if (Directory.Exists(theFilePath) == false)//如果不存在就创建file文件夹 //{ // Directory.CreateDirectory(theFilePath); //} //StreamWriter sw = null; 判断文件是否存在 //if (File.Exists(theFullName)) //{ // sw = File.AppendText(theFullName); //} //else //{ // sw = File.CreateText(theFullName);//创建该文件 //} 导出传盘文件 开始写入 //sw.WriteLine(theContent); 关闭流 //sw.Close(); } catch (Exception ex) { } } }}

用的话就就是在登录系统后连接服务器

 SocketClient socketClient = null;

 socketClient = SocketClient.GetInstance();
 //socketClient.ReceivedMsg = new SocketClient.ReceivedMsgHandler(socketClient_ReceivedMsg);
 socketClient.BeginConnect();

发送消息

  SocketClient sc = SocketClient.GetInstance();

  sc.SendMsg("test", msg.Msg,this._userName);

聊天接收消息

SocketClient socketClient = SocketClient.GetInstance();

socketClient.ReceivedMsg = new SocketClient.ReceivedMsgHandler(socketClient_ReceivedMsg);

这里是在聊天的模块接口socket的消息,这是一个比较懒的写法,按说把应该把消息统一接收,然后用prism的模块之间的通信机制来实现聊天模块的消息接收,因为现在SocketClient是一个单例,你在一个模块设置ReceivedMsg之后,另一个模块设置的ReceivedMsg应该就无效了,,,,这里实际用的话不能像我这样写,,,,后续我也会改掉

然后看一下测试结果

未登录状态

登录成功后

这些吃了吗。。。。都是代码写死的调用发消息的接口,可以忽略

然后手动发一个消息看看

没问题,可以发送成功,没有启动多个客户端,只是能看到服务端收到了消息

再看看表情消息

也可以

然后试试接收消息

没问题

然后试试左侧的消息数量

先点击一边把之前的都去掉

这里因为是测试,直接代码指定的是张三3发来的消息

然后关闭程序看服务端

基本的功能都实现了,后续就是不断的完善了

posted on
2019-04-05 01:07 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/10657770.html

你可能感兴趣的文章
sql语句的进化--hibernate篇
查看>>
python爬虫之cookie
查看>>
2017年5月29号课堂笔记
查看>>
HDU4247【瞎搞】
查看>>
lightoj 1125【背包·从n个选m个】
查看>>
HDU 1243 反恐训练营(最长公共序列)
查看>>
mysql数据库隔离级别
查看>>
(六)buildroot使用详解
查看>>
chrome修改UserAgent,调试
查看>>
Source Insight4.0 试用。。试用。。试用。。
查看>>
python循环for,range,xrange;while
查看>>
hadoop的节点间的通信
查看>>
论如何制做一个工程APP的测试内容
查看>>
Django系列(一)
查看>>
第二类斯特林数
查看>>
url override and HttpSession implements session for form
查看>>
日常方法
查看>>
解决Ueditor在bootstarp 模态框中全屏问题
查看>>
POJ 1006 Biorhythms
查看>>
dubbo+zookeeper注册服务报错问题:No service registed on zookeeper
查看>>