局域网之间的通讯实现

局域网之间通讯有很多种方法,比如可以用数据库存储的方式实现,这里是用Socket来实现的,用Socket来通讯的话可以说是有点麻烦的,因为要保持各个用户与服务器之间的连接,连接一断便不能通讯了,所以个人觉得这个地方比较麻烦;
要实现Socket通讯的话首先可以把它分成两个项目来区别,一个是服务器项目(Server),一个是客户端项目(Client)。
服务器项目的实现可以大致的分成 部分,1:创建一个总连接点,这个连接点负责与客户端的连接,我们不能把连接和通讯都引用到一个连接上,这样服务器会崩溃的,而每个用户都是独立的,所以我们要利用线程来创建一个新的通讯实例,这个连接和通讯各个用户之间都是互不干扰的了,还有一个要注意的就是跨线程调用控件的话是不行的,所以我们又要利用委托存放要调用的功能在用this.Invoke()的方法来跨线程引用控件,接下来就是具体实现响应通讯了;
客户端相对来说要更容易些,创建一个客户端连接实例,与远程服务器连接起来,然后就是大致的通讯实现功能了。
下面是我个人的实现代码和实现的心得,附加了大致的注释,实现了群聊,私聊功能。

通讯类(Communication):

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

namespace Server
{
    [Serializable]
    public class Communication//通讯
    {
            public string Name { get; set; }
            public string Ip { get; set; }//Ip地址
        public string Port { get; set; }//端口号
        public string Message { get; set; }//发送的消息
        public int Types { get; set; }
            //1代表聊天信息 2代表客户端人物信息
        public bool IsFistLogin { get; set; }
            public string ToEndPoint { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Server
{
    [Serializable]
    public class ServerReturnInfo
    {
            public Communication comm { get; set; }//通讯类
        public Socket client { get; set; }
    }
}

服务器类(Server):

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Server
{
    public partial class forServer : Form
    {
        public forServer()
        {
            InitializeComponent();
        }

        private delegate void ListDelegate(Communication comm);
        private ListDelegate listInfo = null;//添加成员
        private delegate void MessageDelegate(Communication comm);
        private MessageDelegate MessageInfo = null;//添加消息
        private delegate void SendDelegate(ServerReturnInfo sri);
        private SendDelegate SendInfo = null;
        private delegate void EndDelegate(Communication commun);
        private EndDelegate EndInfo = null;
        private List<Socket> socketList = new List<Socket>();//成员集合
        private Socket server = null;
        private void 开启服务ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int port = 0;
            server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            if (!int.TryParse(txtPort.Text, out port))
                port = 8080;
            EndPoint endPoint = new IPEndPoint(IPAddress.Any,port);
            server.Bind(endPoint);
            server.Listen(1000);
            rtbMessage.Text = "服务器已经打开!";
            Thread t = new Thread(GetClient);
            t.Start(server);
        }
        public void GetClient(object s)//获取客户端实例
        {
            Socket server = s as Socket;
            Socket client = null;
            while(true)
            {
                try
                {
                    client = server.Accept();
                }
                catch (Exception)
                {
                    return;
                }
                socketList.Add(client);//把客户端实例添加到集合中
                DisMantle(client);
                Thread t2 = new Thread(ReceiveInfo);
                t2.Start(client);
            }
        }
        //客户端人物信息绑定与上线提醒
        public void DisMantle(Socket client)
        {
            string endPoint = client.RemoteEndPoint.ToString();
            string ip = endPoint.Split(':')[0];
            string port = endPoint.Split(':')[1];
            string name = Dns.GetHostEntry(ip).HostName;
            Communication comm = new Communication()
            {
                Name = name,
                Ip = ip,
                Port = port,
                Message = name + "上线了!"
            };
            //通过委托来进行对控件的跨线程修改
            //绑定客户端人物信息到ListView控件上
            listInfo = new ListDelegate(BindListView);
            this.Invoke(listInfo, comm);
            //添加聊天消息  
            MessageInfo = new MessageDelegate(AddMessage);
            this.Invoke(MessageInfo, comm);
            ServerReturnInfo sri = new ServerReturnInfo()
            {
                comm = comm,
                client = client
            };
            SendInfo = new SendDelegate(SendInfos);
            this.Invoke(SendInfo, sri);
        }

        public void SendInfos(object c) //发送列表成员信息到客户端
        {
            ServerReturnInfo sri = c as ServerReturnInfo;
            byte[] b = null;
            foreach (Socket s in socketList)
            {
                sri.comm.Types = 2;
                sri.comm.IsFistLogin = true;
                for (int i = 0; i < lvInfo.Items.Count; i++)
                {
                    sri.comm.Name = lvInfo.Items[i].SubItems[0].Text;
                    sri.comm.Ip = lvInfo.Items[i].SubItems[1].Text;
                    sri.comm.Port = lvInfo.Items[i].SubItems[2].Text;
                    b = SerializeObject(sri.comm);
                    s.Send(b);
                    sri.comm.IsFistLogin = false;
                }
            }
        }
        public void EndClient(Communication commun) //移除成员列表里离线的成员
        {
            foreach (ListViewItem items in lvInfo.Items)
            {
                //如果成员列表上有此用户,则移除
                if (items.SubItems[0].Text.Equals(commun.Name))
                {
                    items.Remove();
                    break;
                }
            }
        }
        public void ReceiveInfo(object o) //获取客户端信息
        {
            Socket client = o as Socket;
            byte[] b = new byte[1024];
            Communication commun = null;
            while (true)
            {
                try
                {
                    client.Receive(b);
                    commun = DeserializeObject(b) as Communication;
                }
                catch (Exception)
                {
                    
                    return;
                }
                if (commun.Types == 1)//客户端发送过来的信息
                {
                    MessageInfo = new MessageDelegate(AddMessage);
                    this.Invoke(MessageInfo, commun);
                    byte[] bb = SerializeObject(commun);
                    foreach (Socket c in socketList)
                    {
                        c.Send(bb);//把客户端的消息发送到其它的客户端
                    }
                }
                else if (commun.Types == 3) //私聊,判断终结点是否一致
                {
                    MessageInfo = new MessageDelegate(AddMessage);
                    this.Invoke(MessageInfo, commun);
                    byte[] bb = SerializeObject(commun);
                    foreach (Socket c in socketList)
                    {
                        string ClientEndPoint = c.RemoteEndPoint.ToString();
                        if (commun.ToEndPoint.Equals(ClientEndPoint))
                        {
                            c.Send(bb);
                            break;
                        }
                    }
                }else if(commun.Types == 4)
                {
                    MessageInfo = new MessageDelegate(AddMessage);
                    this.Invoke(MessageInfo, commun);
                    byte[] bb = SerializeObject(commun);
                    try
                    {
                        foreach (Socket c in socketList)
                        {
                            if (c.Connected)
                                c.Send(bb);//把客户端的离线消息发送到其它的客户端
                        }
                    }
                    catch (Exception)
                    {
                        socketList.Remove(client);//从集合中删除该用户
                        EndInfo = new EndDelegate(EndClient);
                        this.Invoke(EndInfo, commun);
                        client.Dispose();//关闭端口
                        return;
                    }
                }
            }
        }
        public void ClearList() 
        {
            lvInfo.Items.Clear();//清除ListView控件上的数据
        }
        public void BindListView(Communication comm) //绑定客户端人物信息到ListView控件上
        {
            ListViewItem items = new ListViewItem(comm.Name);
            items.SubItems.Add(comm.Ip);
            items.SubItems.Add(comm.Port);
            lvInfo.Items.Add(items);
        }
        public void AddMessage(Communication comm)//添加聊天消息
        {
            rtbMessage.Text += "\n"+comm.Name + ":" + comm.Message;
        }

        public object DeserializeObject(byte[] pBytes)//反序列化二进制为对象
        {
            object newOjb = null;
            if (pBytes == null)
                return newOjb;
            MemoryStream memory = new MemoryStream(pBytes);
            memory.Position = 0;
            BinaryFormatter formatter = new BinaryFormatter();
            newOjb = formatter.Deserialize(memory);
            memory.Close();
            return newOjb;
        }
        public byte[] SerializeObject(object pObj)//序列化对象为二进制的数
        {
            if (pObj == null)
                return null;
            MemoryStream memory = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(memory, pObj);
            memory.Position = 0;
            byte[] read = new byte[memory.Length];
            memory.Read(read, 0, read.Length);
            memory.Close();
            return read;
        }

        private void 退出程序ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void forServer_FormClosing(object sender, FormClosingEventArgs e)
        {
            //检查服务是否还在工作 
        }

        private void forServer_Load(object sender, EventArgs e)
        {
            txtPort.Text = "8080";
        }
    }
}

客户端类(Client):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Server;

namespace Client
{
    public partial class forClient : Form
    {
        public forClient()
        {
            InitializeComponent();
        }

        private delegate void ListDelegate(Communication comm);
        private ListDelegate listInfo = null;//用于绑定成员
        private delegate void MessageDelegate(Communication comm);
        private MessageDelegate MessageInfo = null;//用于添加聊天消息
        private delegate void ClearDelegate();
        private ClearDelegate ClearInfo = null;//用于清除成员列表
        private delegate void EndDelegate(Communication commun);
        private EndDelegate EndInfo = null;
        Socket client = null;
        EndPoint endPoint = null;
        private void 开启服务ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int port = 0;
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            if (!int.TryParse(txtPort.Text, out port))
                port = 8080;
            endPoint = new IPEndPoint(IPAddress.Parse(txtIP.Text), port);
            client.Connect(endPoint);
            rtbMessage.Text = "连接服务器成功!";
            Thread t = new Thread(ReceiveInfo);
            t.Start(client);
        }
        public void ClearList() //清除成员列表
        {
            this.lvInfo.Clear();
        }
        public void EndClient(Communication commun) //移除成员列表里离线的成员
        {
            foreach (ListViewItem items in lvInfo.Items)
            {
                //如果成员列表上有此用户,则移除
                if (items.SubItems[0].Text.Equals(commun.Name))
                {
                    items.Remove();
                    break;
                }
            }
        }
        public void ReceiveInfo(object c)//接收服务器的信息
        {
            byte[] b = new byte[1024];
            Socket client = c as Socket;
            ClearInfo = new ClearDelegate(ClearList);
            while(true)
            {
                try
                {
                    client.Receive(b);
                }
                catch (Exception)
                {
                    client.Dispose();
                    return;
                }
                Communication comm = DeserializeObject(b) as Communication;
                if (comm.Types == 2)//服务器回发过来的信息
                {
                    listInfo = new ListDelegate(BindListView);
                    this.Invoke(listInfo, comm);
                }
                else if (comm.Types == 1 || comm.Types == 3)
                {
                    MessageInfo = new MessageDelegate(AddMessage);
                    this.Invoke(MessageInfo, comm);
                }
                else //下线执行
                {
                    MessageInfo = new MessageDelegate(AddMessage);
                    this.Invoke(MessageInfo, comm);
                    EndInfo = new EndDelegate(EndClient);
                    this.Invoke(EndInfo,comm);
                }
            }
        }
        public void BindListView(Communication comm) //绑定客户端人物信息到ListView控件上
        {
            if(comm.IsFistLogin)
            {
                lvInfo.Items.Clear();//第一次添加的时候(判定为true时)清除原有的旧成员
            }
            ListViewItem items = new ListViewItem(comm.Name);
            items.SubItems.Add(comm.Ip);
            items.SubItems.Add(comm.Port);
            lvInfo.Items.Add(items);
        }
        public void AddMessage(Communication comm)//添加聊天消息
        {
            rtbMessage.Text += "\n"+comm.Name + ":" + comm.Message;
        }
        public object DeserializeObject(byte[] pBytes)//反序列化二进制为对象
        {
            object newOjb = null;
            if (pBytes == null)
                return newOjb;
            MemoryStream memory = new MemoryStream(pBytes);
            memory.Position = 0;
            BinaryFormatter formatter = new BinaryFormatter();
            newOjb = formatter.Deserialize(memory);
            memory.Close();
            return newOjb;
        }
        public byte[] SerializeObject(object pObj)//序列化对象为二进制的数
        {
            if (pObj == null)
                return null;
            MemoryStream memory = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(memory, pObj);
            memory.Position = 0;
            byte[] read = new byte[memory.Length];
            memory.Read(read, 0, read.Length);
            memory.Close();
            return read;
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            Communication comm = new Communication() {
                Name = Dns.GetHostName(),
                Message = txtMessage.Text,
                Types = 1
            };
            if (lvInfo.SelectedItems.Count > 0)//私聊
            {
                comm.Types = 3;
                string ePoint = lvInfo.SelectedItems[0].SubItems[1].Text +":"+ lvInfo.SelectedItems[0].SubItems[2].Text;
                comm.ToEndPoint = ePoint;
            }
            byte[] b = SerializeObject(comm);
            client.Send(b);
            lvInfo.SelectedItems.Clear();//清除选中的个数
        }

        private void 退出程序ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Communication comm = new Communication()
            {
                Name = Dns.GetHostName(),
                Message = "下线了!",
                Types = 4//用户下线类型
            };
            byte[] b = SerializeObject(comm);
            client.Send(b);
            client.Dispose();
            Application.Exit();
        }

        private void forClient_Load(object sender, EventArgs e)
        {
            //127.0.0.1 用于获取本机IP
            txtIP.Text = "192.168.1.100";
            txtPort.Text = "8080";
        }
    }
}

 

posted @ 2013-12-25 16:49  skynetfy  阅读(362)  评论(0编辑  收藏  举报