C#编写聊天软件服务端
标签:前缀 sele delegate nbsp eric res main stop cas
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Net.Sockets;
6 using System.IO;
7
8 namespace SyncChatServer
9 {
10 class User
11 {
12 public TcpClient client { get; private set; }
13 public BinaryReader br { get; private set; }
14 public BinaryWriter bw { get; private set; }
15 public string userName { get; set; }
16
17 public User(TcpClient client)
18 {
19 this.client = client;
20 NetworkStream networkStream = client.GetStream();
21 br = new BinaryReader(networkStream);
22 bw = new BinaryWriter(networkStream);
23 }
24
25 public void Close()
26 {
27 br.Close();
28 bw.Close();
29 client.Close();
30 }
31
32 }
33 }
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.Text;
8 using System.Windows.Forms;
9 using System.Net;
10 using System.Net.Sockets;
11 using System.Threading;
12 using System.IO;
13
14 namespace SyncChatServer
15 {
16 public partial class MainForm : Form
17 {
18 ///
19 /// 保存连接的所有用户
20 ///
21 private List userList = new List();
22
23 ///
24 /// 服务器IP地址
25 /// ;
26 private string ServerIP;
27
28 ///
29 /// 监听端口
30 ///
31 private int port;
32 private TcpListener myListener;
33
34 ///
35 /// 是否正常退出所有接收线程
36 ///
37 bool isNormalExit = false;
38
39 public MainForm()
40 {
41 InitializeComponent();
42 lst_State.HorizontalScrollbar = true;
43 btn_Stop.Enabled = false;
44 SetServerIPAndPort();
45 }
46
47 ///
48 /// 根据当前程序目录的文本文件‘ServerIPAndPort.txt’内容来设定IP和端口
49 /// 格式:127.0.0.1:8885
50 ///
51 private void SetServerIPAndPort()
52 {
53 FileStream fs = new FileStream("ServerIPAndPort.txt", FileMode.Open);
54 StreamReader sr = new StreamReader(fs);
55 string IPAndPort = sr.ReadLine();
56 ServerIP = IPAndPort.Split(‘:‘)[0]; //设定IP
57 port = int.Parse(IPAndPort.Split(‘:‘)[1]); //设定端口
58 sr.Close();
59 fs.Close();
60 }
61
62
63 ///
64 /// 开始监听
65 ///
66 ///
67 ///
68 private void btn_Start_Click(object sender, EventArgs e)
69 {
70 myListener = new TcpListener(IPAddress.Parse(ServerIP), port);
71 myListener.Start();
72 AddItemToListBox(string.Format("开始在{0}:{1}监听客户连接", ServerIP, port));
73 //创建一个线程监客户端连接请求
74 Thread myThread = new Thread(ListenClientConnect);
75 myThread.Start();
76 btn_Start.Enabled = false;
77 btn_Stop.Enabled = true;
78 }
79
80 ///
81 /// 接收客户端连接
82 ///
83 private void ListenClientConnect()
84 {
85 TcpClient newClient = null;
86 while (true)
87 {
88 try
89 {
90 newClient = myListener.AcceptTcpClient();
91 }
92 catch
93 {
94 //当单击‘停止监听’或者退出此窗体时 AcceptTcpClient() 会产生异常
95 //因此可以利用此异常退出循环
96 break;
97 }
98 //每接收一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息;
99 User user = new User(newClient);
100 Thread threadReceive = new Thread(ReceiveData);
101 threadReceive.Start(user);
102 userList.Add(user);
103 AddItemToListBox(string.Format("[{0}]进入", newClient.Client.RemoteEndPoint));
104 AddItemToListBox(string.Format("当前连接用户数:{0}", userList.Count));
105 }
106
107 }
108
109 ///
110 /// 处理接收的客户端信息
111 ///
112 /// 客户端信息
113 private void ReceiveData(object userState)
114 {
115 User user = (User)userState;
116 TcpClient client = user.client;
117 while (isNormalExit == false)
118 {
119 string receiveString = null;
120 try
121 {
122 //从网络流中读出字符串,此方法会自动判断字符串长度前缀
123 receiveString = user.br.ReadString();
124 }
125 catch (Exception)
126 {
127 if (isNormalExit == false)
128 {
129 AddItemToListBox(string.Format("与[{0}]失去联系,已终止接收该用户信息", client.Client.RemoteEndPoint));
130 RemoveUser(user);
131 }
132 break;
133 }
134 AddItemToListBox(string.Format("来自[{0}]:{1}",user.client.Client.RemoteEndPoint,receiveString));
135 string[] splitString = receiveString.Split(‘,‘);
136 switch(splitString[0])
137 {
138 case "Login":
139 user.userName = splitString[1];
140 SendToAllClient(user,receiveString);
141 break;
142 case "Logout":
143 SendToAllClient(user,receiveString);
144 RemoveUser(user);
145 return;
146 case "Talk":
147 string talkString = receiveString.Substring(splitString[0].Length + splitString[1].Length + 2);
148 AddItemToListBox(string.Format("{0}对{1}说:{2}",user.userName,splitString[1],talkString));
149 SendToClient(user,"talk," + user.userName + "," + talkString);
150 foreach(User target in userList)
151 {
152 if(target.userName == splitString[1] && user.userName != splitString[1])
153 {
154 SendToClient(target,"talk," + user.userName + "," + talkString);
155 break;
156 }
157 }
158 break;
159 default:
160 AddItemToListBox("什么意思啊:" + receiveString);
161 break;
162 }
163 }
164 }
165
166 ///
167 /// 发送消息给所有客户
168 ///
169 /// 指定发给哪个用户
170 /// 信息内容
171 private void SendToAllClient(User user, string message)
172 {
173 string command = message.Split(‘,‘)[0].ToLower();
174 if (command == "login")
175 {
176 //获取所有客户端在线信息到当前登录用户
177 for (int i = 0; i )
178 {
179 SendToClient(user, "login," + userList[i].userName);
180 }
181 //把自己上线,发送给所有客户端
182 for (int i = 0; i )
183 {
184 if (user.userName != userList[i].userName)
185 {
186 SendToClient(userList[i], "login," + user.userName);
187 }
188 }
189 }
190 else if(command == "logout")
191 {
192 for (int i = 0; i )
193 {
194 if (userList[i].userName != user.userName)
195 {
196 SendToClient(userList[i], message);
197 }
198 }
199 }
200 }
201
202 ///
203 /// 发送 message 给 user
204 ///
205 /// 指定发给哪个用户
206 /// 信息内容
207 private void SendToClient(User user, string message)
208 {
209 try
210 {
211 //将字符串写入网络流,此方法会自动附加字符串长度前缀
212 user.bw.Write(message);
213 user.bw.Flush();
214 AddItemToListBox(string.Format("向[{0}]发送:{1}", user.userName, message));
215 }
216 catch
217 {
218 AddItemToListBox(string.Format("向[{0}]发送信息失败",user.userName));
219 }
220 }
221
222 ///
223 /// 移除用户
224 ///
225 /// 指定要移除的用户
226 private void RemoveUser(User user)
227 {
228 userList.Remove(user);
229 user.Close();
230 AddItemToListBox(string.Format("当前连接用户数:{0}",userList.Count));
231 }
232
233 private delegate void AddItemToListBoxDelegate(string str);
234 ///
235 /// 在ListBox中追加状态信息
236 ///
237 /// 要追加的信息
238 private void AddItemToListBox(string str)
239 {
240 if (lst_State.InvokeRequired)
241 {
242 AddItemToListBoxDelegate d = AddItemToListBox;
243 lst_State.Invoke(d, str);
244 }
245 else
246 {
247 lst_State.Items.Add(str);
248 lst_State.SelectedIndex = lst_State.Items.Count - 1;
249 lst_State.ClearSelected();
250 }
251 }
252
253 ///
254 /// 停止监听
255 ///
256 ///
257 ///
258 private void btn_Stop_Click(object sender, EventArgs e)
259 {
260 AddItemToListBox("开始停止服务,并依次使用户退出!");
261 isNormalExit = true;
262 for (int i = userList.Count - 1; i >= 0; i--)
263 {
264 RemoveUser(userList[i]);
265 }
266 //通过停止监听让 myListener.AcceptTcpClient() 产生异常退出监听线程
267 myListener.Stop();
268 btn_Start.Enabled = true;
269 btn_Stop.Enabled = false;
270 }
271
272 ///
273 /// 关闭窗口时触发的事件
274 ///
275 ///
276 ///
277 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
278 {
279 if (myListener != null)
280 btn_Stop.PerformClick(); //引发 btn_Stop 的Click事件
281 }
282 }
283 }
C#编写聊天软件服务端
标签:前缀 sele delegate nbsp eric res main stop cas
原文地址:https://www.cnblogs.com/ddwk/p/8742978.html
评论