Tcpclient简单聊天程序

来源:互联网 发布:淘宝天猫店招尺寸 编辑:程序博客网 时间:2024/05/16 11:35

以前C/S通讯这一块都是基于套接字(Sockets)编程,但是面对业务逻辑复杂的C/S系统,通讯这一块往往都是被封装好了的,前几天写的一个小小窗体聊天程序,主要是练习一下C#封装的TcpListener、TcpClient以及NetworkStream的使用,直接看图上代码:

[csharp] view plaincopyprint?
  1. using System;
  2. using System.Drawing;
  3. using System.Collections;
  4. using System.ComponentModel;
  5. using System.Windows.Forms;
  6. using System.Data;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Threading;
  10. using System.IO;
  11. namespace ChartTestServer
  12. {
  13. public partial class Form1 : Form
  14. {
  15. public Form1()
  16. {
  17. InitializeComponent();
  18. }
  19. private NetworkStream networkStream;
  20. private StreamReader streamReader;
  21. private StreamWriter streamWriter;
  22. private Socket socketForClient;
  23. private TcpListener tcpListener;
  24. private Thread serverThread;// 启动服务线程
  25. private Thread recvThread;// 接收信息线程
  26. private void button1_Click(object sender, EventArgs e)
  27. {
  28. serverThread = new Thread(new ThreadStart(Listen));
  29. serverThread.Start();
  30. }
  31. //[STAThread]
  32. private void Listen()
  33. {
  34. try
  35. {
  36. Int32 port = Int32.Parse(txtPort.Text);
  37. IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
  38. tcpListener = new TcpListener(ipAddress, port);
  39. // 开始侦听
  40. tcpListener.Start();
  41. listBox1.Items.Add("服务已经启动!");
  42. button1.Enabled = false;
  43. button2.Enabled = true;
  44. // 返回可以用以处理连接的Socket实例
  45. socketForClient = tcpListener.AcceptSocket();
  46. // 如果返回值是"true",则产生的套节字已经接受来自远方的连接请求
  47. if (socketForClient.Connected)
  48. {
  49. button3.Enabled = true;
  50. listBox1.Items.Add("客户端成功连接上服务器!");
  51. // 创建networkStream对象通过网络套节字来接受和发送数据
  52. networkStream = new NetworkStream(socketForClient);
  53. // 从当前数据流中读取一行字符,返回值是字符串
  54. streamReader = new StreamReader(networkStream);
  55. streamWriter = new StreamWriter(networkStream);
  56. recvThread = new Thread(new ThreadStart(RecvData));
  57. recvThread.Start();
  58. }
  59. }
  60. catch (Exception exc)
  61. {
  62. MessageBox.Show(exc.Message, "Server提示");
  63. }
  64. }
  65. // 接收服务器发来的信息
  66. private void RecvData()
  67. {
  68. string msg = streamReader.ReadLine();
  69. // 如果不是接收到客户端发来的退出信息,则不断接收信息
  70. while (!msg.Equals("exit"))
  71. {
  72. //statusChart1.Value = Convert.ToInt32(msg);
  73. listBox1.Items.Add("收到信息: " + msg);
  74. msg = streamReader.ReadLine();
  75. }
  76. // 如果接收到客户的退出信息,则退出服务
  77. button1.Enabled = true;
  78. button2.Enabled = false;
  79. button3.Enabled = false;
  80. listBox1.Items.Add("客户已经关闭");
  81. listBox1.Items.Add("服务器关闭");
  82. // 关闭资源
  83. ReleaseResource();
  84. }
  85. private void button3_Click(object sender, EventArgs e)
  86. {
  87. Thread sendThread = new Thread(new ThreadStart(SendData));
  88. sendThread.Start();
  89. }
  90. private void SendData()
  91. {
  92. if (txtMsg.Text != "")
  93. {
  94. listBox1.Items.Add("发送信息: " + txtMsg.Text);
  95. // 往当前的数据流中写入一行字符串
  96. streamWriter.WriteLine(txtMsg.Text);
  97. // 刷新当前数据流中的数据
  98. streamWriter.Flush();
  99. txtMsg.Text = ""; // 清空
  100. }
  101. else
  102. {
  103. MessageBox.Show("发送信息不能为空","提示");
  104. }
  105. }
  106. private void button2_Click(object sender, EventArgs e)
  107. {
  108. try
  109. {
  110. if (button3.Enabled == true)
  111. {
  112. // 停止服务后,允许 启动服务,但是不允许发送消息
  113. button1.Enabled = true;
  114. button2.Enabled = false;
  115. button3.Enabled = false;
  116. string exitMsg = "exit"; // 要退出时,发送 exit 信息给客户端
  117. streamWriter.WriteLine(exitMsg);
  118. // 刷新当前数据流中的数据
  119. streamWriter.Flush();
  120. listBox1.Items.Add("服务器关闭");
  121. // 释放资源
  122. recvThread.Abort();
  123. ReleaseResource();
  124. }
  125. else
  126. {
  127. // 停止服务后,允许 启动服务,但是不允许发送消息
  128. button1.Enabled = true;
  129. button2.Enabled = false;
  130. button3.Enabled = false;
  131. listBox1.Items.Add("服务器关闭");
  132. // 关闭TCP连接,关闭线程
  133. tcpListener.Stop();
  134. serverThread.Abort();
  135. }
  136. }
  137. catch (Exception exc)
  138. {
  139. MessageBox.Show(exc.Message, "Server提示");
  140. }
  141. }
  142. // 释放资源
  143. private void ReleaseResource()
  144. {
  145. networkStream.Close();
  146. streamReader.Close();
  147. streamWriter.Close();
  148. socketForClient.Shutdown(SocketShutdown.Both);
  149. socketForClient.Close();
  150. tcpListener.Stop();
  151. }
  152. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  153. {
  154. // 在未停止 服务 前,不允许关闭窗体
  155. if (button1.Enabled == false)
  156. {
  157. MessageBox.Show("请先停止服务!", "Server提示");
  158. e.Cancel = true;
  159. }
  160. }
  161. private void Form1_Load(object sender, EventArgs e)
  162. {
  163. // 在没有启动服务器之前,不允许停止服务以及发送信息
  164. button2.Enabled = false;
  165. button3.Enabled = false;
  166. }
  167. }

[csharp] view plaincopyprint?
  1. using System;
  2. using System.Drawing;
  3. using System.Collections;
  4. using System.ComponentModel;
  5. using System.Windows.Forms;
  6. using System.Data;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Threading;
  10. using System.IO;
  11. namespace ChartTest
  12. {
  13. public partial class Form1 : Form
  14. {
  15. public Form1()
  16. {
  17. InitializeComponent();
  18. }
  19. private NetworkStream networkStream;
  20. private StreamReader streamReader;
  21. private StreamWriter streamWriter;
  22. private TcpClient myclient;
  23. private Thread recvThread; // 接收信息线程
  24. private Thread sendThread;// 发送信息线程
  25. private Thread serverThread;// 服务线程
  26. private Thread st;
  27. private void button1_Click(object sender, EventArgs e)
  28. {
  29. serverThread = new Thread(new ThreadStart(Connection));
  30. serverThread.Start();
  31. }
  32. private void Connection()
  33. {
  34. /*
  35. try
  36. {
  37. IPAddress ipAddress = IPAddress.Parse(txtIP.Text);
  38. Int32 port = Int32.Parse(txtPort.Text);
  39. IPEndPoint ipe = new IPEndPoint(ipAddress, port);
  40. myclient = new TcpClient();
  41. myclient.Connect(ipe);
  42. }
  43. catch
  44. {
  45. MessageBox.Show("没有连接到服务器!");
  46. return;
  47. }
  48. */
  49. try
  50. {
  51. IPAddress ipAddress = IPAddress.Parse(txtIP.Text);
  52. Int32 port = Int32.Parse(txtPort.Text);
  53. string hostName = Dns.GetHostEntry(ipAddress).HostName;
  54. myclient = new TcpClient(hostName, port);
  55. }
  56. catch
  57. {
  58. MessageBox.Show("没有连接到服务器!");
  59. return;
  60. }
  61. listBox1.Items.Add("客户端成功连接上服务器!");
  62. button1.Enabled = false; // 连接上了,不让按“连接”按钮
  63. button2.Enabled = true;
  64. button3.Enabled = true;
  65. networkStream = myclient.GetStream();
  66. streamReader = new StreamReader(networkStream);
  67. streamWriter = new StreamWriter(networkStream);
  68. // 创建接收信息线程,并启动
  69. recvThread = new Thread(new ThreadStart(RecvData));
  70. recvThread.Start();
  71. }
  72. // 接收数据
  73. private void RecvData()
  74. {
  75. string s = streamReader.ReadLine();
  76. // 如果没接到服务器退出的消息,则继续接收信息
  77. while (s!=null&&!s.Equals("exit"))
  78. {
  79. listBox1.Items.Add("收到信息:" + s);
  80. s = streamReader.ReadLine();
  81. }
  82. // 收到服务器退出的消息,释放资源
  83. listBox1.Items.Add("服务器关闭");
  84. listBox1.Items.Add("客户端关闭");
  85. button1.Enabled = true;
  86. button2.Enabled = false;
  87. button3.Enabled = false;
  88. // streamReader.Close();
  89. // streamWriter.Close();
  90. // networkStream.Close();
  91. // myclient.Close();
  92. ReleaseResouce();
  93. }
  94. private void button2_Click(object sender, EventArgs e)
  95. {
  96. button1.Enabled = true; // 按了停止之后,“连接”按钮可以用,“发送”不能用
  97. button2.Enabled = false;
  98. button3.Enabled = false;
  99. string exitMsg = "exit"; // 要退出时,发送 exit 信息给服务器
  100. streamWriter.WriteLine(exitMsg);
  101. //刷新当前数据流中的数据
  102. streamWriter.Flush();
  103. listBox1.Items.Add("客户端关闭");
  104. ReleaseResouce();
  105. }
  106. private void button3_Click(object sender, EventArgs e)
  107. {
  108. // 启动发送线程
  109. sendThread = new Thread(new ThreadStart(SendData));
  110. sendThread.Start();
  111. }
  112. // 发送数据
  113. private void SendData()
  114. {
  115. // 发送信息不允许为空
  116. if (txtMsg.Text == "")
  117. {
  118. MessageBox.Show("发送的信息不能为空!");
  119. txtMsg.Focus();
  120. return;
  121. }
  122. try
  123. {
  124. //往当前的数据流中写入一行字符串
  125. streamWriter.WriteLine(txtMsg.Text);
  126. //刷新当前数据流中的数据
  127. streamWriter.Flush();
  128. listBox1.Items.Add("发送信息:" + txtMsg.Text);
  129. txtMsg.Text = ""; // 清空
  130. }
  131. catch (Exception exc)
  132. {
  133. MessageBox.Show(exc.Message, "ClientClient提示");
  134. }
  135. }
  136. private void Form1_Load(object sender, EventArgs e)
  137. {
  138. // 在未连接服务器前,不能发送信息和停止
  139. button2.Enabled = false;
  140. button3.Enabled = false;
  141. }
  142. // 释放资源
  143. private void ReleaseResouce()
  144. {
  145. networkStream.Close();
  146. streamReader.Close();
  147. streamWriter.Close();
  148. if (sendThread!=null&&sendThread.IsAlive)
  149. {
  150. sendThread.Abort();
  151. }
  152. if (recvThread.IsAlive)
  153. {
  154. recvThread.Abort();
  155. }
  156. if (serverThread.IsAlive)
  157. {
  158. serverThread.Abort();
  159. }
  160. myclient.Close();
  161. }
  162. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  163. {
  164. // 如果是在连接中,则不允许关闭窗口
  165. if (button1.Enabled == false)
  166. {
  167. MessageBox.Show("请先停止连接!","ClientClient提示");
  168. e.Cancel = true;
  169. }
  170. }
  171. private void button4_Click(object sender, EventArgs e)
  172. {
  173. // 启动发送线程
  174. st = new Thread(new ThreadStart(SeData));
  175. st.Start();
  176. }
  177. // 发送数据
  178. private void SeData()
  179. {
  180. Random r = new Random();
  181. for (int i = 0; i < 10000; i++)
  182. {
  183. Thread.Sleep(400);
  184. try
  185. {
  186. //往当前的数据流中写入一行字符串
  187. streamWriter.WriteLine(r.Next(80).ToString());
  188. //刷新当前数据流中的数据
  189. streamWriter.Flush();
  190. listBox1.Items.Add("发送信息:" + r.Next(80).ToString());
  191. }
  192. catch (Exception exc)
  193. {
  194. MessageBox.Show(exc.Message, "ClientClient提示");
  195. }
  196. }
  197. }
  198. private void button5_Click(object sender, EventArgs e)
  199. {
  200. st.Abort();
  201. }
  202. }
  203. }

关于线程访问控件问题,为了偷懒,我直接屏蔽了,在Program.cs的Main()函数中加入:

[csharp] view plaincopyprint?
  1. System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls =false;

例子源码:http://download.csdn.net/detail/wangqiuyun/4502341
原创粉丝点击