局域网之间通讯有很多种方法,比如可以用数据库存储的方式实现,还可以用udp来实现,这里是用tcp来实现的,用tcp来通讯的话可以说是有点麻烦的,因为要保持各个用户与服务器之间的连接,连接一断便不能通讯了,所以个人觉得这个地方比较麻烦;

要实现Socket通讯的话首先可以把它分成两个项目来区别,一个是服务器项目(Server),一个是客户端项目(Client)。

服务器项目的实现可以大致的分成 部分,1:创建一个总连接点,这个连接点负责与客户端的连接,我们不能把连接和通讯都引用到一个连接上,这样服务器会崩溃的,而每个用户都是独立的,所以我们要利用线程来创建一个新的通讯实例,这个连接和通讯各个用户之间都是互不干扰的了,还有一个要注意的就是跨线程调用控件的话是不行的,所以我们又要利用委托存放要调用的功能在用this.Invoke()的方法来跨线程引用控件,接下来就是具体实现响应通讯了;

客户端相对来说要更容易些,创建一个客户端连接实例,与远程服务器连接起来,然后就是大致的通讯实现功能了。

下面是我个人的实现代码和实现的心得,附加了大致的注释,实现了群聊,私聊等功能。

 

通讯类(Communication)

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Server
 8 {
 9     [Serializable]
10     public class Communication//通讯
11     {
12             public string Name { get; set; }
13             public string Ip { get; set; }//Ip地址
14         public string Port { get; set; }//端口号
15         public string Message { get; set; }//发送的消息
16         public int Types { get; set; }
17             //1代表聊天信息 2代表客户端人物信息
18         public bool IsFistLogin { get; set; }
19             public string ToEndPoint { get; set; }
20     }
21 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net.Sockets;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace Server
 9 {
10     [Serializable]
11     public class ServerReturnInfo
12     {
13             public Communication comm { get; set; }//通讯类
14         public Socket client { get; set; }
15     }
16 }
View Code

服务器类(Server)

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.IO;
  7 using System.Linq;
  8 using System.Net;
  9 using System.Net.Sockets;
 10 using System.Runtime.Serialization.Formatters.Binary;
 11 using System.Text;
 12 using System.Threading;
 13 using System.Threading.Tasks;
 14 using System.Windows.Forms;
 15 
 16 namespace Server
 17 {
 18     public partial class forServer : Form
 19     {
 20         public forServer()
 21         {
 22             InitializeComponent();
 23         }
 24 
 25         private delegate void ListDelegate(Communication comm);
 26         private ListDelegate listInfo = null;//添加成员
 27         private delegate void MessageDelegate(Communication comm);
 28         private MessageDelegate MessageInfo = null;//添加消息
 29         private delegate void SendDelegate(ServerReturnInfo sri);
 30         private SendDelegate SendInfo = null;
 31         private delegate void EndDelegate(Communication commun);
 32         private EndDelegate EndInfo = null;
 33         private List<Socket> socketList = new List<Socket>();//成员集合
 34         private Socket server = null;
 35         private void 开启服务ToolStripMenuItem_Click(object sender, EventArgs e)
 36         {
 37             int port = 0;
 38             server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
 39             if (!int.TryParse(txtPort.Text, out port))
 40                 port = 8080;
 41             EndPoint endPoint = new IPEndPoint(IPAddress.Any,port);
 42             server.Bind(endPoint);
 43             server.Listen(1000);
 44             rtbMessage.Text = "服务器已经打开!";
 45             Thread t = new Thread(GetClient);
 46             t.Start(server);
 47         }
 48         public void GetClient(object s)//获取客户端实例
 49         {
 50             Socket server = s as Socket;
 51             Socket client = null;
 52             while(true)
 53             {
 54                 try
 55                 {
 56                     client = server.Accept();
 57                 }
 58                 catch (Exception)
 59                 {
 60                     return;
 61                 }
 62                 socketList.Add(client);//把客户端实例添加到集合中
 63                 DisMantle(client);
 64                 Thread t2 = new Thread(ReceiveInfo);
 65                 t2.Start(client);
 66             }
 67         }
 68         //客户端人物信息绑定与上线提醒
 69         public void DisMantle(Socket client)
 70         {
 71             string endPoint = client.RemoteEndPoint.ToString();
 72             string ip = endPoint.Split(':')[0];
 73             string port = endPoint.Split(':')[1];
 74             string name = Dns.GetHostEntry(ip).HostName;
 75             Communication comm = new Communication()
 76             {
 77                 Name = name,
 78                 Ip = ip,
 79                 Port = port,
 80                 Message = name + "上线了!"
 81             };
 82             //通过委托来进行对控件的跨线程修改
 83             //绑定客户端人物信息到ListView控件上
 84             listInfo = new ListDelegate(BindListView);
 85             this.Invoke(listInfo, comm);
 86             //添加聊天消息  
 87             MessageInfo = new MessageDelegate(AddMessage);
 88             this.Invoke(MessageInfo, comm);
 89             ServerReturnInfo sri = new ServerReturnInfo()
 90             {
 91                 comm = comm,
 92                 client = client
 93             };
 94             SendInfo = new SendDelegate(SendInfos);
 95             this.Invoke(SendInfo, sri);
 96         }
 97 
 98         public void SendInfos(object c) //发送列表成员信息到客户端
 99         {
100             ServerReturnInfo sri = c as ServerReturnInfo;
101             byte[] b = null;
102             foreach (Socket s in socketList)
103             {
104                 sri.comm.Types = 2;
105                 sri.comm.IsFistLogin = true;
106                 for (int i = 0; i < lvInfo.Items.Count; i++)
107                 {
108                     sri.comm.Name = lvInfo.Items[i].SubItems[0].Text;
109                     sri.comm.Ip = lvInfo.Items[i].SubItems[1].Text;
110                     sri.comm.Port = lvInfo.Items[i].SubItems[2].Text;
111                     b = SerializeObject(sri.comm);
112                     s.Send(b);
113                     sri.comm.IsFistLogin = false;
114                 }
115             }
116         }
117         public void EndClient(Communication commun) //移除成员列表里离线的成员
118         {
119             foreach (ListViewItem items in lvInfo.Items)
120             {
121                 //如果成员列表上有此用户,则移除
122                 if (items.SubItems[0].Text.Equals(commun.Name))
123                 {
124                     items.Remove();
125                     break;
126                 }
127             }
128         }
129         public void ReceiveInfo(object o) //获取客户端信息
130         {
131             Socket client = o as Socket;
132             byte[] b = new byte[1024];
133             Communication commun = null;
134             while (true)
135             {
136                 try
137                 {
138                     client.Receive(b);
139                     commun = DeserializeObject(b) as Communication;
140                 }
141                 catch (Exception)
142                 {
143                     
144                     return;
145                 }
146                 if (commun.Types == 1)//客户端发送过来的信息
147                 {
148                     MessageInfo = new MessageDelegate(AddMessage);
149                     this.Invoke(MessageInfo, commun);
150                     byte[] bb = SerializeObject(commun);
151                     foreach (Socket c in socketList)
152                     {
153                         c.Send(bb);//把客户端的消息发送到其它的客户端
154                     }
155                 }
156                 else if (commun.Types == 3) //私聊,判断终结点是否一致
157                 {
158                     MessageInfo = new MessageDelegate(AddMessage);
159                     this.Invoke(MessageInfo, commun);
160                     byte[] bb = SerializeObject(commun);
161                     foreach (Socket c in socketList)
162                     {
163                         string ClientEndPoint = c.RemoteEndPoint.ToString();
164                         if (commun.ToEndPoint.Equals(ClientEndPoint))
165                         {
166                             c.Send(bb);
167                             break;
168                         }
169                     }
170                 }else if(commun.Types == 4)
171                 {
172                     MessageInfo = new MessageDelegate(AddMessage);
173                     this.Invoke(MessageInfo, commun);
174                     byte[] bb = SerializeObject(commun);
175                     try
176                     {
177                         foreach (Socket c in socketList)
178                         {
179                             if (c.Connected)
180                                 c.Send(bb);//把客户端的离线消息发送到其它的客户端
181                         }
182                     }
183                     catch (Exception)
184                     {
185                         socketList.Remove(client);//从集合中删除该用户
186                         EndInfo = new EndDelegate(EndClient);
187                         this.Invoke(EndInfo, commun);
188                         client.Dispose();//关闭端口
189                         return;
190                     }
191                 }
192             }
193         }
194         public void ClearList() 
195         {
196             lvInfo.Items.Clear();//清除ListView控件上的数据
197         }
198         public void BindListView(Communication comm) //绑定客户端人物信息到ListView控件上
199         {
200             ListViewItem items = new ListViewItem(comm.Name);
201             items.SubItems.Add(comm.Ip);
202             items.SubItems.Add(comm.Port);
203             lvInfo.Items.Add(items);
204         }
205         public void AddMessage(Communication comm)//添加聊天消息
206         {
207             rtbMessage.Text += "\n"+comm.Name + ":" + comm.Message;
208         }
209 
210         public object DeserializeObject(byte[] pBytes)//反序列化二进制为对象
211         {
212             object newOjb = null;
213             if (pBytes == null)
214                 return newOjb;
215             MemoryStream memory = new MemoryStream(pBytes);
216             memory.Position = 0;
217             BinaryFormatter formatter = new BinaryFormatter();
218             newOjb = formatter.Deserialize(memory);
219             memory.Close();
220             return newOjb;
221         }
222         public byte[] SerializeObject(object pObj)//序列化对象为二进制的数
223         {
224             if (pObj == null)
225                 return null;
226             MemoryStream memory = new MemoryStream();
227             BinaryFormatter formatter = new BinaryFormatter();
228             formatter.Serialize(memory, pObj);
229             memory.Position = 0;
230             byte[] read = new byte[memory.Length];
231             memory.Read(read, 0, read.Length);
232             memory.Close();
233             return read;
234         }
235 
236         private void 退出程序ToolStripMenuItem_Click(object sender, EventArgs e)
237         {
238             Application.Exit();
239         }
240 
241         private void forServer_FormClosing(object sender, FormClosingEventArgs e)
242         {
243             //检查服务是否还在工作 
244         }
245 
246         private void forServer_Load(object sender, EventArgs e)
247         {
248             txtPort.Text = "8080";
249         }
250     }
251 }
View Code

客户端类(Client)

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.IO;
  7 using System.Linq;
  8 using System.Net;
  9 using System.Net.Sockets;
 10 using System.Runtime.Serialization.Formatters.Binary;
 11 using System.Text;
 12 using System.Threading;
 13 using System.Threading.Tasks;
 14 using System.Windows.Forms;
 15 using Server;
 16 
 17 namespace Client
 18 {
 19     public partial class forClient : Form
 20     {
 21         public forClient()
 22         {
 23             InitializeComponent();
 24         }
 25 
 26         private delegate void ListDelegate(Communication comm);
 27         private ListDelegate listInfo = null;//用于绑定成员
 28         private delegate void MessageDelegate(Communication comm);
 29         private MessageDelegate MessageInfo = null;//用于添加聊天消息
 30         private delegate void ClearDelegate();
 31         private ClearDelegate ClearInfo = null;//用于清除成员列表
 32         private delegate void EndDelegate(Communication commun);
 33         private EndDelegate EndInfo = null;
 34         Socket client = null;
 35         EndPoint endPoint = null;
 36         private void 开启服务ToolStripMenuItem_Click(object sender, EventArgs e)
 37         {
 38             int port = 0;
 39             client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 40             if (!int.TryParse(txtPort.Text, out port))
 41                 port = 8080;
 42             endPoint = new IPEndPoint(IPAddress.Parse(txtIP.Text), port);
 43             client.Connect(endPoint);
 44             rtbMessage.Text = "连接服务器成功!";
 45             Thread t = new Thread(ReceiveInfo);
 46             t.Start(client);
 47         }
 48         public void ClearList() //清除成员列表
 49         {
 50             this.lvInfo.Clear();
 51         }
 52         public void EndClient(Communication commun) //移除成员列表里离线的成员
 53         {
 54             foreach (ListViewItem items in lvInfo.Items)
 55             {
 56                 //如果成员列表上有此用户,则移除
 57                 if (items.SubItems[0].Text.Equals(commun.Name))
 58                 {
 59                     items.Remove();
 60                     break;
 61                 }
 62             }
 63         }
 64         public void ReceiveInfo(object c)//接收服务器的信息
 65         {
 66             byte[] b = new byte[1024];
 67             Socket client = c as Socket;
 68             ClearInfo = new ClearDelegate(ClearList);
 69             while(true)
 70             {
 71                 try
 72                 {
 73                     client.Receive(b);
 74                 }
 75                 catch (Exception)
 76                 {
 77                     client.Dispose();
 78                     return;
 79                 }
 80                 Communication comm = DeserializeObject(b) as Communication;
 81                 if (comm.Types == 2)//服务器回发过来的信息
 82                 {
 83                     listInfo = new ListDelegate(BindListView);
 84                     this.Invoke(listInfo, comm);
 85                 }
 86                 else if (comm.Types == 1 || comm.Types == 3)
 87                 {
 88                     MessageInfo = new MessageDelegate(AddMessage);
 89                     this.Invoke(MessageInfo, comm);
 90                 }
 91                 else //下线执行
 92                 {
 93                     MessageInfo = new MessageDelegate(AddMessage);
 94                     this.Invoke(MessageInfo, comm);
 95                     EndInfo = new EndDelegate(EndClient);
 96                     this.Invoke(EndInfo,comm);
 97                 }
 98             }
 99         }
100         public void BindListView(Communication comm) //绑定客户端人物信息到ListView控件上
101         {
102             if(comm.IsFistLogin)
103             {
104                 lvInfo.Items.Clear();//第一次添加的时候(判定为true时)清除原有的旧成员
105             }
106             ListViewItem items = new ListViewItem(comm.Name);
107             items.SubItems.Add(comm.Ip);
108             items.SubItems.Add(comm.Port);
109             lvInfo.Items.Add(items);
110         }
111         public void AddMessage(Communication comm)//添加聊天消息
112         {
113             rtbMessage.Text += "\n"+comm.Name + ":" + comm.Message;
114         }
115         public object DeserializeObject(byte[] pBytes)//反序列化二进制为对象
116         {
117             object newOjb = null;
118             if (pBytes == null)
119                 return newOjb;
120             MemoryStream memory = new MemoryStream(pBytes);
121             memory.Position = 0;
122             BinaryFormatter formatter = new BinaryFormatter();
123             newOjb = formatter.Deserialize(memory);
124             memory.Close();
125             return newOjb;
126         }
127         public byte[] SerializeObject(object pObj)//序列化对象为二进制的数
128         {
129             if (pObj == null)
130                 return null;
131             MemoryStream memory = new MemoryStream();
132             BinaryFormatter formatter = new BinaryFormatter();
133             formatter.Serialize(memory, pObj);
134             memory.Position = 0;
135             byte[] read = new byte[memory.Length];
136             memory.Read(read, 0, read.Length);
137             memory.Close();
138             return read;
139         }
140 
141         private void btnSend_Click(object sender, EventArgs e)
142         {
143             Communication comm = new Communication() {
144                 Name = Dns.GetHostName(),
145                 Message = txtMessage.Text,
146                 Types = 1
147             };
148             if (lvInfo.SelectedItems.Count > 0)//私聊
149             {
150                 comm.Types = 3;
151                 string ePoint = lvInfo.SelectedItems[0].SubItems[1].Text +":"+ lvInfo.SelectedItems[0].SubItems[2].Text;
152                 comm.ToEndPoint = ePoint;
153             }
154             byte[] b = SerializeObject(comm);
155             client.Send(b);
156             lvInfo.SelectedItems.Clear();//清除选中的个数
157         }
158 
159         private void 退出程序ToolStripMenuItem_Click(object sender, EventArgs e)
160         {
161             Communication comm = new Communication()
162             {
163                 Name = Dns.GetHostName(),
164                 Message = "下线了!",
165                 Types = 4//用户下线类型
166             };
167             byte[] b = SerializeObject(comm);
168             client.Send(b);
169             client.Dispose();
170             Application.Exit();
171         }
172 
173         private void forClient_Load(object sender, EventArgs e)
174         {
175             //127.0.0.1 用于获取本机IP
176             txtIP.Text = "192.168.1.100";
177             txtPort.Text = "8080";
178         }
179     }
180 }
View Code

 

 

posted on 2013-12-24 22:08  翻滚的咸鱼  阅读(2118)  评论(0编辑  收藏  举报