博主主要是用了socket的方法去实现了服务器和客户端之间的通信,由于楼主对于socket网络编程这一方面的基础相当薄弱,故也是边学边学,有些地方的代码不够完善还请大神指正!博主还需学习。
首先,先说说服务端方面:服务端采用的是VS的windows form窗体应用程序做的,也是为了方便查看和操作吧。
窗体长这样

首先先声明一个公共类
public class Common { /// <summary> /// 保存服务器来的消息 /// </summary> public static byte[] ReceiveBuffer = new byte[1024 * 1024]; /// <summary> /// 监听用的socket /// </summary> public static Socket ListenSocket; /// <summary> /// 保存所有负责通信用是socket /// </summary> public static Dictionary<string, Socket> connSocket = new Dictionary<string, Socket>(); }服务端首先要开启服务,点击“启动服务器”按钮,则可以从两个TextBox中读取输入的ip地址和端口号的信息,通过这个信息开启服务
void StartServer() { try { string _ip = tbIp.Text; int _point = int.Parse(tbPoint.Text); //创建监听客户端请求的socket Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, PRotocolType.Tcp); //监听用的ip和端口 IPAddress address = IPAddress.Parse(_ip); IPEndPoint point = new IPEndPoint(address, _point); //绑定 socket.Bind(point); socket.Listen(10); //异步 开始监听 socket.BeginAccept(new AsyncCallback(Listen), socket); //禁用当前按钮 btnStart.Enabled = false; //启动时间 startTime.Text = DateTime.Now.ToString(); //底部提示消息 tssMsg.Text = "服务器已经启动"; } catch (Exception ex) { MessageBox.Show(ex.Message); } }开启服务后,异步实现监听和接收消息,以保证服务器不会阻塞。通过接收到的消息的头一个字节——协议位,来判断客户端发送的消息是要做什么的
void Listen(IAsyncResult result) { try { //获取监听的socket Socket clientSocket = result.AsyncState as Socket; //与服务器通信的socket Socket connSocket = clientSocket.EndAccept(result); string ip = connSocket.RemoteEndPoint.ToString(); //连接成功。保存信息 if (!Common.connSocket.ContainsKey(ip)) Common.connSocket.Add(ip, connSocket); //连接成功,更新服务器信息 changeList(connSocket); //等待新的客户端连接 ,相当于循环调用 clientSocket.BeginAccept(new AsyncCallback(Listen), clientSocket); //接收来自客户端信息 ,相当于循环调用 connSocket.BeginReceive(Common.ReceiveBuffer, 0, Common.ReceiveBuffer.Length, 0, new AsyncCallback(Receive), connSocket); } catch (Exception ex) { MessageBox.Show(ex.Message); } } void Receive(IAsyncResult result) { //与客户端通信的socket Socket clientSocket = result.AsyncState as Socket; string ip = clientSocket.RemoteEndPoint.ToString(); try { //获取实际的长度值 int num = clientSocket.EndReceive(result); if (num > 0) { byte[] data = new byte[num]; //复制实际的长度到data字节数组中 Array.Copy(Common.ReceiveBuffer, 0, data, 0, num); //判断协议位 int command = data[0]; switch (command) { case 1: //服务器保存发送方的IP和其棋子的颜色,并寻求配对 MatchingRival(data,ip); break; case 2: //接收发送方发来的移动棋子的消息,并转发给接收方 SendMoveMessageToClient(data); break; case 3: //接收发送方的悔棋消息,并转发给接收方 SendRetractMessageToClient(data); break; case 6: //接收到发送方想要确定接收方是否在线的意愿,并做检测 SendDisconnectMessageToClient(data); break; default: break; } //接收其他信息 clientSocket.BeginReceive(Common.ReceiveBuffer, 0, Common.ReceiveBuffer.Length, 0, new AsyncCallback(Receive), clientSocket); } else //客户端断开 { clientOff(clientSocket); } } catch (Exception ex) { clientOff(clientSocket); } }在介绍每一个从客户端接收的消息是干什么的之前(下一篇再整理),我们要先了解一下changeList(更新列表)和changOnlineCount(更新在线人数)这两个函数 void changeList(Socket socket) { //获取客户端信息 ip和端口号 string ip = socket.RemoteEndPoint.ToString(); //客户端登陆时间 string time = DateTime.Now.ToString(); //跨线程操作ui this.Invoke(new Action(() => { //新增一行 dgvList.Rows.Add(); //获取当前dgvList的行 int rows = dgvList.Rows.Count; //赋值 dgvList.Rows[rows - 1].Cells[0].Value = ip; dgvList.Rows[rows - 1].Cells[1].Value = time; //把ip当作当前行的tag标记一下,为了删除行的时候可以找到该行 dgvList.Rows[rows - 1].Tag = ip; //更新在线人数 changOnlineCount(true); })); } void changOnlineCount(bool tag) { int num = 0; if (tag) num = int.Parse(lbCount.Text) + 1; else num = int.Parse(lbCount.Text) - 1; this.Invoke(new Action(() => { //更新在线人数 lbCount.Text = num.ToString(); if (num == 0) Common.connSocket.Clear(); })); }当有客户端连接的时候,首先会执行一次changeList函数,将所连接的客户端的信息显示在DataGridView里面,并在“在线人数”处+1同样的,当有客户端断开的时候,也会更新列表,“在线人数”-1,删除在DataGridView里面的信息,并关闭该连接
void clientOff(Socket clientSocket) { //从集合删除下线的ip string outIp = clientSocket.RemoteEndPoint.ToString(); if (Common.connSocket.ContainsKey(outIp)) Common.connSocket.Remove(outIp); //更新服务器在线人数 changOnlineCount(false); this.Invoke(new Action(() => { //更新列表 //删除退出的ip for (int i = 0; i < dgvList.Rows.Count; i++) { if (dgvList.Rows[i].Tag.ToString() == outIp) { dgvList.Rows.RemoveAt(i); break; } } })); clientSocket.Shutdown(SocketShutdown.Receive); clientSocket.Close(); }
新闻热点
疑难解答