1. 程式人生 > >C#編寫聊天軟件服務端

C#編寫聊天軟件服務端

cte AD sel public 登錄 客戶端 發送消息 監聽端口 獲取



 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 /// <summary> 19 /// 保存連接的所有用戶 20 /// </summary> 21 private List<User> userList = new List<User>(); 22 23 /// <summary> 24 /// 服務器IP地址 25 /// </summary>; 26 private string ServerIP; 27 28 /// <summary> 29 /// 監聽端口 30 /// </summary> 31 private int port; 32 private TcpListener myListener; 33 34 /// <summary> 35 /// 是否正常退出所有接收線程 36 /// </summary> 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 /// <summary> 48 /// 根據當前程序目錄的文本文件‘ServerIPAndPort.txt’內容來設定IP和端口 49 /// 格式:127.0.0.1:8885 50 /// </summary> 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 /// <summary> 64 /// 開始監聽 65 /// </summary> 66 /// <param name="sender"></param> 67 /// <param name="e"></param> 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 /// <summary> 81 /// 接收客戶端連接 82 /// </summary> 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 /// <summary> 110 /// 處理接收的客戶端信息 111 /// </summary> 112 /// <param name="userState">客戶端信息</param> 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 /// <summary> 167 /// 發送消息給所有客戶 168 /// </summary> 169 /// <param name="user">指定發給哪個用戶</param> 170 /// <param name="message">信息內容</param> 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 < userList.Count; i++) 178 { 179 SendToClient(user, "login," + userList[i].userName); 180 } 181 //把自己上線,發送給所有客戶端 182 for (int i = 0; i < userList.Count; 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 < userList.Count; i++) 193 { 194 if (userList[i].userName != user.userName) 195 { 196 SendToClient(userList[i], message); 197 } 198 } 199 } 200 } 201 202 /// <summary> 203 /// 發送 message 給 user 204 /// </summary> 205 /// <param name="user">指定發給哪個用戶</param> 206 /// <param name="message">信息內容</param> 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 /// <summary> 223 /// 移除用戶 224 /// </summary> 225 /// <param name="user">指定要移除的用戶</param> 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 /// <summary> 235 /// 在ListBox中追加狀態信息 236 /// </summary> 237 /// <param name="str">要追加的信息</param> 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 /// <summary> 254 /// 停止監聽 255 /// </summary> 256 /// <param name="sender"></param> 257 /// <param name="e"></param> 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 /// <summary> 273 /// 關閉窗口時觸發的事件 274 /// </summary> 275 /// <param name="sender"></param> 276 /// <param name="e"></param> 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#編寫聊天軟件服務端