Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 676|回复: 0

开发交流:以C#编写的Socket服务器的Android手机聊天室Demo

[复制链接]

该用户从未签到

发表于 2011-10-24 10:45:16 | 显示全部楼层 |阅读模式
内容摘要

  1.程序架构

  2.通信协议

  3.服务器源代码

  4.客户端源代码

  5.运行效果


一、程序架构

  在开发一个聊天室程序时,我们可以使用Socket、Remoting、WCF这些具有双向通信的协议或框架。而现在,我正要实现一个C#语言作为服务器端、Android作为客户端的聊天室。由于服务器端和客户端不是同一语言(C#和java),所有我选择了Socket作为通信协议。

图1.1所示,我们可以看出:android手机客户端A向服务器端发送消息,服务器端收到消息后,又把消息推送到android手机客户端B。





我们知道,在C#语言中使用Socket技术需要“四部曲”,即“Bind”,“Listen”,“Accept”,“Receive”。然而Socket编程不像WCF那样面向对象。而且对应每个请求都用同一种方式处理。作为习惯面向对象编程的我来说,编写一个传统的Socket程序很不爽。绞尽脑汁,我们将数据传输的格式改为json(JavaScript Object Notation 是一种轻量级的数据交换格式),面对对象的问题就解决了。

  假设程序的服务契约有两个方法:“登陆”和“发送消息”。调用登陆的方法,就传送方法名(Method Name)为“Logon”的json数据;调用发送消息的方法,就传送方法名为“Send”的json数据。返回的数据中也使用json格式,这样在android客户端中也能知道是哪个方法的返回值了。

三、服务器源代码

首先需要编写一个处理客户端消息的接口:IResponseManager。
    public interface IResponseManager

    {

        void Write(Socket sender, IList<Socket> cliens, IDictionary<string, object> param);

    }
复制代码其次,我们知道,换了是WCF编程的话,就需要在服务契约中写两个方法:“登陆”和“发送消息”。由于这里是Socket编程,我们实现之前写的IResponseManager接口,一个实现作为“登陆”的方法,另一个实现作为“发送消息”的方法。
public class LogonResponseManager : IResponseManager

    {

        public void Write(System.Net.Sockets.Socket sender, IList<System.Net.Sockets.Socket> cliens, IDictionary<string, object> param)

        {

            Console.WriteLine("客户端({0})登陆", sender.Handle);

            var response = new SocketResponse

            {

                Method = "Logon",

                DateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),

                Result = new { UserName = param["UserName"].ToString() }

            };



            JavaScriptSerializer jss = new JavaScriptSerializer();

            string context = jss.Serialize(response);

            Console.WriteLine("登陆发送的数据为:{0}", context);

            sender.Send(Encoding.UTF8.GetBytes(context + "\n"));

        }

    }









public class SendResponseManager : IResponseManager

    {

        public void Write(System.Net.Sockets.Socket sender, IList<System.Net.Sockets.Socket> cliens, IDictionary<string, object> param)

        {

            Console.WriteLine("客户端({0})发送消息", sender.Handle);

            var msgList = param["Message"] as IEnumerable<object>;

            if (msgList == null)

            {

                return;

            }



            var response = new SocketResponse

            {

                Method = "Send",

                DateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),

                Result = new

                {

                    UserName = param["UserName"].ToString(),

                    Message = msgList.Select(s => s.ToString()).ToArray()

                }

            };



            JavaScriptSerializer jss = new JavaScriptSerializer();

            string context = jss.Serialize(response);

            Console.WriteLine("消息发送的数据为:{0}", context);



            Parallel.ForEach(cliens, (item) =>

            {

                try

                {

                    item.Send(Encoding.UTF8.GetBytes(context + "\n"));

                }

                catch { };

            });

        }

    }
复制代码最后在Socket程序中使用反射加“策略模式”调用这两个接口实现类。
            var typeName = "SocketServer." + request.Method + "ResponseManager, SocketServer";

            Console.WriteLine("反射类名为:" + typeName);



            Type type = Type.GetType(typeName);

            if (type == null)

            {

                return;

            }



            var manager = Activator.CreateInstance(type) as IResponseManager;

            manager.Write(sender, this.socketClientSesson.Select(s => s.Key).ToList(),

                request.Param as IDictionary<string, object>);
复制代码完整的Socket服务器代码如下: public class SocketHost

    {

        private IDictionary<Socket, byte[]> socketClientSesson = new Dictionary<Socket, byte[]>();



        public int Port { get; set; }



        public void Start()

        {

            var socketThread = new Thread(() =>

            {

                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPEndPoint iep = new IPEndPoint(IPAddress.Any, this.Port);



                //绑定到通道上

                socket.Bind(iep);



                //侦听

                socket.Listen(6);



                //通过异步来处理

                socket.BeginAccept(new AsyncCallback(Accept), socket);



            });



            socketThread.Start();



            Console.WriteLine("服务器已启动");

        }



        private void Accept(IAsyncResult ia)

        {

            Socket socket = ia.AsyncState as Socket;

            var client = socket.EndAccept(ia);



            socket.BeginAccept(new AsyncCallback(Accept), socket);



            byte[] buf = new byte[1024];

            this.socketClientSesson.Add(client, buf);



            try

            {

                client.BeginReceive(buf, 0, buf.Length, SocketFlags.None, new AsyncCallback(Receive), client);

                string sessionId = client.Handle.ToString();

                Console.WriteLine("客户端({0})已连接", sessionId);

            }

            catch (Exception ex)

            {

                Console.WriteLine("监听请求时出错:\r\n" + ex.ToString());

            }

        }



        private void Receive(IAsyncResult ia)

        {

            var client = ia.AsyncState as Socket;



            if (client == null || !this.socketClientSesson.ContainsKey(client))

            {

                return;

            }



            int count = client.EndReceive(ia);



            byte[] buf = this.socketClientSesson[client];



            if (count > 0)

            {

                try

                {

                    client.BeginReceive(buf, 0, buf.Length, SocketFlags.None, new AsyncCallback(Receive), client);

                    string context = Encoding.UTF8.GetString(buf, 0, count);

                    Console.WriteLine("接收的数据为:", context);



                    this.Response(client, context);

                }

                catch (Exception ex)

                {

                    Console.WriteLine("接收的数据出错:\r\n{0}", ex.ToString());

                }

            }

            else

            {

                try

                {

                    string sessionId = client.Handle.ToString();

                    client.Disconnect(true);

                    this.socketClientSesson.Remove(client);

                    Console.WriteLine("客户端({0})已断开", sessionId);

                }

                catch (Exception ex)

                {

                    Console.WriteLine("客户端已断开出错" + ex.ToString());

                }

            }

        }



        private void Response(Socket sender, string context)

        {

            SocketRequest request = null;

            JavaScriptSerializer jss = new JavaScriptSerializer();

            request = jss.Deserialize(context, typeof(SocketRequest)) as SocketRequest;



            if (request == null)

            {

                return;

            }



            var typeName = "SocketServer." + request.Method + "ResponseManager, SocketServer";

            Console.WriteLine("反射类名为:" + typeName);



            Type type = Type.GetType(typeName);

            if (type == null)

            {

                return;

            }



            var manager = Activator.CreateInstance(type) as IResponseManager;

            manager.Write(sender, this.socketClientSesson.Select(s => s.Key).ToList(),

                request.Param as IDictionary<string, object>);

        }

    }
复制代码最后,json数据传输的实体对象为:    [Serializable]

    public class SocketRequest

    {

        public string Method { get; set; }



        public string DateTime { get; set; }



        public object Param { get; set; }

    }



    [Serializable]

    public class SocketResponse

    {

        public string Method { get; set; }



        public string DateTime { get; set; }



        public object Result { get; set; }

    }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-11 07:48 , Processed in 0.409091 second(s), 48 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表