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.Sockets;
10 using System.Net;
11 using System.IO;
12 using System.Threading;
13
14 namespace SyncChatClient
15 {
16 public partial class MainForm : Form
17 {
18 private string ServerIP; //IP
19 private int port; //端口
20 private bool isExit = false;
21 private TcpClient client;
22 private BinaryReader br;
23 private BinaryWriter bw;
24 public MainForm()
25 {
26 InitializeComponent();
27 Random r = new Random((int)DateTime.Now.Ticks);
28 txt_UserName.Text = "user" + r.Next(100, 999);
29 lst_OnlineUser.HorizontalScrollbar = true;
30 SetServerIPAndPort();
31 }
32
33 /// <summary>
34 /// 根据当前程序目录的文本文件‘ServerIPAndPort.txt’内容来设定IP和端口
35 /// 格式:127.0.0.1:8885
36 /// </summary>
37 private void SetServerIPAndPort()
38 {
39 try
40 {
41 FileStream fs = new FileStream("ServerIPAndPort.txt", FileMode.Open);
42 StreamReader sr = new StreamReader(fs);
43 string IPAndPort = sr.ReadLine();
44 ServerIP = IPAndPort.Split(':')[0]; //设定IP
45 port = int.Parse(IPAndPort.Split(':')[1]); //设定端口
46 sr.Close();
47 fs.Close();
48 }
49 catch (Exception ex)
50 {
51 MessageBox.Show("配置IP与端口失败,错误原因:" + ex.Message);
52 Application.Exit();
53 }
54 }
55
56 /// <summary>
57 /// 【登陆】按钮事件
58 /// </summary>
59 /// <param name="sender"></param>
60 /// <param name="e"></param>
61 private void btn_Login_Click(object sender, EventArgs e)
62 {
63 btn_Login.Enabled = false;
64 try
65 {
66 //此处为方便演示,实际使用时要将Dns.GetHostName()改为服务器域名
67 //IPAddress ipAd = IPAddress.Parse("182.150.193.7");
68 client = new TcpClient();
69 client.Connect(IPAddress.Parse(ServerIP), port);
70 AddTalkMessage("连接成功");
71 }
72 catch(Exception ex)
73 {
74 AddTalkMessage("连接失败,原因:" + ex.Message);
75 btn_Login.Enabled = true;
76 return;
77 }
78 //获取网络流
79 NetworkStream networkStream = client.GetStream();
80 //将网络流作为二进制读写对象
81 br = new BinaryReader(networkStream);
82 bw = new BinaryWriter(networkStream);
83 SendMessage("Login," + txt_UserName.Text);
84 Thread threadReceive = new Thread(new ThreadStart(ReceiveData));
85 threadReceive.IsBackground = true;
86 threadReceive.Start();
87 }
88
89 /// <summary>
90 /// 处理服务器信息
91 /// </summary>
92 private void ReceiveData()
93 {
94 string receiveString = null;
95 while (isExit == false)
96 {
97 try
98 {
99 //从网络流中读出字符串
100 //此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
101 receiveString = br.ReadString();
102 }
103 catch
104 {
105 if (isExit == false)
106 {
107 MessageBox.Show("与服务器失去连接");
108 }
109 break;
110 }
111 string[] splitString = receiveString.Split(',');
112 string command = splitString[0].ToLower();
113 switch (command)
114 {
115 case "login": //格式: login,用户名
116 AddOnline(splitString[1]);
117 break;
118 case "logout": //格式: logout,用户名
119 RemoveUserName(splitString[1]);
120 break;
121 case "talk": //格式: talk,用户名,对话信息
122 AddTalkMessage(splitString[1] + ":\r\n");
123 AddTalkMessage(receiveString.Substring(splitString[0].Length + splitString[1].Length+2));
124 break;
125 default:
126 AddTalkMessage("什么意思啊:" + receiveString);
127 break;
128 }
129 }
130 Application.Exit();
131 }
132
133 /// <summary>
134 /// 向服务端发送消息
135 /// </summary>
136 /// <param name="message"></param>
137 private void SendMessage(string message)
138 {
139 try
140 {
141 //将字符串写入网络流,此方法会自动附加字符串长度前缀
142 bw.Write(message);
143 bw.Flush();
144 }
145 catch
146 {
147 AddTalkMessage("发送失败");
148 }
149 }
150
151 private delegate void AddTalkMessageDelegate(string message);
152 /// <summary>
153 /// 在聊天对话框(txt_Message)中追加聊天信息
154 /// </summary>
155 /// <param name="message"></param>
156 private void AddTalkMessage(string message)
157 {
158 if (txt_Message.InvokeRequired)
159 {
160 AddTalkMessageDelegate d = new AddTalkMessageDelegate(AddTalkMessage);
161 txt_Message.Invoke(d, new object[] { message });
162 }
163 else
164 {
165 txt_Message.AppendText(message + Environment.NewLine);
166 txt_Message.ScrollToCaret();
167 }
168 }
169
170 private delegate void AddOnlineDelegate(string message);
171 /// <summary>
172 /// 在在线框(lst_Online)中添加其他客户端信息
173 /// </summary>
174 /// <param name="userName"></param>
175 private void AddOnline(string userName)
176 {
177 if (lst_OnlineUser.InvokeRequired)
178 {
179 AddOnlineDelegate d = new AddOnlineDelegate(AddOnline);
180 lst_OnlineUser.Invoke(d, new object[] { userName });
181 }
182 else
183 {
184 lst_OnlineUser.Items.Add(userName);
185 lst_OnlineUser.SelectedIndex = lst_OnlineUser.Items.Count - 1;
186 lst_OnlineUser.ClearSelected();
187 }
188 }
189
190 private delegate void RemoveUserNameDelegate(string userName);
191 /// <summary>
192 /// 在在线框(lst_Online)中移除不在线的客户端信息
193 /// </summary>
194 /// <param name="userName"></param>
195 private void RemoveUserName(string userName)
196 {
197 if (lst_OnlineUser.InvokeRequired)
198 {
199 RemoveUserNameDelegate d = new RemoveUserNameDelegate(RemoveUserName);
200 lst_OnlineUser.Invoke(d, userName);
201 }
202 else
203 {
204 lst_OnlineUser.Items.Remove(userName);
205 lst_OnlineUser.SelectedIndex = lst_OnlineUser.Items.Count - 1;
206 lst_OnlineUser.ClearSelected();
207 }
208 }
209
210 /// <summary>
211 /// 【发送】按钮单击事件
212 /// </summary>
213 /// <param name="sender"></param>
214 /// <param name="e"></param>
215 private void btn_Send_Click(object sender, EventArgs e)
216 {
217 if (lst_OnlineUser.SelectedIndex != -1)
218 {
219 SendMessage("Talk," + lst_OnlineUser.SelectedItem + "," + txt_SendText.Text + "\r\n");
220 txt_SendText.Clear();
221 }
222 else
223 {
224 MessageBox.Show("请先在【当前在线】中选择一个对话着");
225 }
226 }
227
228 /// <summary>
229 /// 窗体关闭事件
230 /// </summary>
231 /// <param name="sender"></param>
232 /// <param name="e"></param>
233 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
234 {
235 //未与服务器连接前 client 为 null
236 if (client != null)
237 {
238 try
239 {
240 SendMessage("Logout," + txt_UserName.Text);
241 isExit = true;
242 br.Close();
243 bw.Close();
244 client.Close();
245 }
246 catch
247 {
248 }
249 }
250 }
251
252 /// <summary>
253 /// 在发送信息的文本框中按下【Enter】键触发的事件
254 /// </summary>
255 /// <param name="sender"></param>
256 /// <param name="e"></param>
257 private void txt_SendText_KeyPress(object sender, KeyPressEventArgs e)
258 {
259 if (e.KeyChar == (char)Keys.Return)
260 {
261 //触发【发送】按钮的单击事件
262 btn_Send.PerformClick();
263 }
264 }
265
266 private void btn_LoadOnlineUser_Click(object sender, EventArgs e)
267 {
268
269 }
270
271
272 }
273 }