1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Net;
8 using System.Net.Sockets;
9 using System.Text;
10 using System.Threading;
11 using System.Threading.Tasks;
12 using System.Windows.Forms;
13
14 namespace _02ChatServer
15 {
16 public partial class ChatServer : Form
17 {
18 public ChatServer()
19 {
20 Control.CheckForIllegalCrossThreadCalls = false;
21 InitializeComponent();
22 }
23 Socket skListen = null;//为了服务器能够控制监听的停止,把监听的socket声明在外面.
24 Dictionary<string, Socket> dicClient = new Dictionary<string, Socket>();
25 private void button1_Click(object sender, EventArgs e)
26 {
27 if (skListen == null)
28 {
29 //开启一个Socket进行监听通讯的端口
30 skListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
31 }
32 //绑定IP和端口号
33 skListen.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999));
34 //设置监听的队列
35 skListen.Listen(10);
36 lblState.ForeColor = Color.Green;
37 lblState.Font = new Font("黑体", 30);
38 lblState.Text = "监听中..";
39
40
41
42 Thread thread = new Thread(new ThreadStart(() => {
43 //不断接收用户的连接请求.
44 while (true)
45 {
46 //准备客户端的连接;
47 Socket skConnetion = skListen.Accept();//这句话会阻塞主线程,所以要把他放在一个单独的线程中.
48 //当客户端连接的时候将IP端口号和Socket帮定到一个集合中
49 dicClient.Add(skConnetion.RemoteEndPoint.ToString(), skConnetion);
50 listboxClients.Items.Add( skConnetion.RemoteEndPoint.ToString());
51 txtLog.AppendText(skConnetion.RemoteEndPoint.ToString() + "已经连接上了.."+Environment.NewLine);
52 //当一个用户连接上的时候如果不发送消息的时候就会阻塞当前线程所有要再创建一个线程来接收用户的消息.
53 //使用线程池来创建一个线程执行客户端接收用户消息,下面的lamada表达式通过传入客户端的连接socket来实现函数的内部访问客户端连接的socket,当传入的不是lanmeda表达式的时候可以使用这种方法传入客户端socket.
54 ThreadPool.QueueUserWorkItem(new WaitCallback(obj=>{
55 Socket skReceive = skConnetion as Socket;
56
57 byte[] buffer=new byte[1024 * 1024 * 4];
58 //因为客户端发送的消息不是只发一个,要不断的重复接收用户的信息发送
59 while (true)
60 {
61
62 int count= skReceive.Receive(buffer);
63 if (count == 0)
64 {
65 //用户退出了
66 txtLog.AppendText("客户端"+skReceive.RemoteEndPoint.ToString()+"已退出");
67 dicClient.Remove(skReceive.RemoteEndPoint.ToString());
68 listboxClients.Items.Remove(skReceive.RemoteEndPoint.ToString());
69 break;
70 }
71 string msg = Encoding.UTF8.GetString(buffer,0,count);
72 txtLog.AppendText("客户端"+skConnetion.RemoteEndPoint.ToString()+"发来消息:"+msg+Environment.NewLine);//易外耳门特
73 }
74
75 }),skConnetion);
76 }
77
78 }));
79 thread.IsBackground = true;
80 thread.Start();
81
82
83 }
84
85 private void button3_Click(object sender, EventArgs e)
86 {
87 //判断是否选中了要通讯的ip端口
88 if (listboxClients.SelectedItem != null)
89 {
90 //根据用户的选中的端口,找到通讯的scoket
91 Socket sk = dicClient[listboxClients.SelectedItem.ToString()];
92 if (sk != null)
93 {
94 //把用户输入的消息转化成字节数组
95 byte[] buffer = Encoding.UTF8.GetBytes(txtSendMsg.Text.Trim());
96 byte[] sendBuffer=new byte[buffer.Length+1];
97
98 Buffer.BlockCopy(buffer, 0, sendBuffer, 1, buffer.Length);
99 //向客户端发送了消息
100 sk.Send(sendBuffer);
101 //写入日志
102 txtLog.AppendText("服务器向[" + listboxClients.SelectedItem.ToString() + "]发送了:" + txtSendMsg.Text + Environment.NewLine);
103 }
104 }
105 else
106 {
107 MessageBox.Show("请选中要发送消息的客户端");
108 }
109 }
110
111 private void button4_Click(object sender, EventArgs e)
112 {
113 if (listboxClients.SelectedItem != null)
114 {
115 //1.根据选中的客户端端口ip选择通讯的socket
116 Socket skClient= dicClient[listboxClients.SelectedItem.ToString()];
117 skClient.Send(new byte[] { 2 });//发送一个标记2来提示客户端发送的是一个闪屏
118
119 }
120 else
121 {
122 MessageBox.Show("请选择要发送的客户端");
123 }
124 }
125 }
126 }