以前C/S通讯这一块都是基于套接字(Sockets)编程,但是面对业务逻辑复杂的C/S系统,通讯这一块往往都是被封装好了的,前几天写的一个小小窗体聊天程序,主要是练习一下C#封装的TcpListener、TcpClient以及NetworkStream的使用,直接看图上代码:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace ChartTestServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private NetworkStream networkStream;
private StreamReader streamReader;
private StreamWriter streamWriter;
private Socket socketForClient;
private TcpListener tcpListener;
private Thread serverThread; // 启动服务线程
private Thread recvThread;// 接收信息线程
private void button1_Click(object sender, EventArgs e)
{
serverThread = new Thread(new ThreadStart(Listen));
serverThread.Start();
}
//[STAThread]
private void Listen()
{
try
{
Int32 port = Int32.Parse(txtPort.Text);
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
tcpListener = new TcpListener(ipAddress, port);
// 开始侦听
tcpListener.Start();
listBox1.Items.Add("服务已经启动!");
button1.Enabled = false;
button2.Enabled = true;
// 返回可以用以处理连接的Socket实例
socketForClient = tcpListener.AcceptSocket();
// 如果返回值是"true",则产生的套节字已经接受来自远方的连接请求
if (socketForClient.Connected)
{
button3.Enabled = true;
listBox1.Items.Add("客户端成功连接上服务器!");
// 创建networkStream对象通过网络套节字来接受和发送数据
networkStream = new NetworkStream(socketForClient);
// 从当前数据流中读取一行字符,返回值是字符串
streamReader = new StreamReader(networkStream);
streamWriter = new StreamWriter(networkStream);
recvThread = new Thread(new ThreadStart(RecvData));
recvThread.Start();
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Server提示");
}
}
// 接收服务器发来的信息
private void RecvData()
{
string msg = streamReader.ReadLine();
// 如果不是接收到客户端发来的退出信息,则不断接收信息
while (!msg.Equals("exit"))
{
//statusChart1.Value = Convert.ToInt32(msg);
listBox1.Items.Add("收到信息: " + msg);
msg = streamReader.ReadLine();
}
// 如果接收到客户的退出信息,则退出服务
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
listBox1.Items.Add("客户已经关闭");
listBox1.Items.Add("服务器关闭");
// 关闭资源
ReleaseResource();
}
private void button3_Click(object sender, EventArgs e)
{
Thread sendThread = new Thread(new ThreadStart(SendData));
sendThread.Start();
}
private void SendData()
{
if (txtMsg.Text != "")
{
listBox1.Items.Add("发送信息: " + txtMsg.Text);
// 往当前的数据流中写入一行字符串
streamWriter.WriteLine(txtMsg.Text);
// 刷新当前数据流中的数据
streamWriter.Flush();
txtMsg.Text = ""; // 清空
}
else
{
MessageBox.Show("发送信息不能为空", "提示");
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
if (button3.Enabled == true)
{
// 停止服务后,允许 启动服务,但是不允许发送消息
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
string exitMsg = "exit"; // 要退出时,发送 exit 信息给客户端
streamWriter.WriteLine(exitMsg);
// 刷新当前数据流中的数据
streamWriter.Flush();
listBox1.Items.Add("服务器关闭");
// 释放资源
recvThread.Abort();
ReleaseResource();
}
else
{
// 停止服务后,允许 启动服务,但是不允许发送消息
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
listBox1.Items.Add("服务器关闭");
// 关闭TCP连接,关闭线程
tcpListener.Stop();
serverThread.Abort();
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Server提示");
}
}
// 释放资源
private void ReleaseResource()
{
networkStream.Close();
streamReader.Close();
streamWriter.Close();
socketForClient.Shutdown(SocketShutdown.Both);
socketForClient.Close();
tcpListener.Stop();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// 在未停止 服务 前,不允许关闭窗体
if (button1.Enabled == false)
{
MessageBox.Show("请先停止服务!", "Server提示");
e.Cancel = true;
}
}
private void Form1_Load(object sender, EventArgs e)
{
// 在没有启动服务器之前,不允许停止服务以及发送信息
button2.Enabled = false;
button3.Enabled = false;
}
}
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace ChartTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private NetworkStream networkStream;
private StreamReader streamReader;
private StreamWriter streamWriter;
private TcpClient myclient;
private Thread recvThread; // 接收信息线程
private Thread sendThread; // 发送信息线程
private Thread serverThread;// 服务线程
private Thread st;
private void button1_Click(object sender, EventArgs e)
{
serverThread = new Thread(new ThreadStart(Connection));
serverThread.Start();
}
private void Connection()
{
/*
try
{
IPAddress ipAddress = IPAddress.Parse(txtIP.Text);
Int32 port = Int32.Parse(txtPort.Text);
IPEndPoint ipe = new IPEndPoint(ipAddress, port);
myclient = new TcpClient();
myclient.Connect(ipe);
}
catch
{
MessageBox.Show("没有连接到服务器!");
return;
}
*/
try
{
IPAddress ipAddress = IPAddress.Parse(txtIP.Text);
Int32 port = Int32.Parse(txtPort.Text);
string hostName = Dns.GetHostEntry(ipAddress).HostName;
myclient = new TcpClient(hostName, port);
}
catch
{
MessageBox.Show("没有连接到服务器!");
return;
}
listBox1.Items.Add("客户端成功连接上服务器!");
button1.Enabled = false; // 连接上了,不让按“连接”按钮
button2.Enabled = true;
button3.Enabled = true;
networkStream = myclient.GetStream();
streamReader = new StreamReader(networkStream);
streamWriter = new StreamWriter(networkStream);
// 创建接收信息线程,并启动
recvThread = new Thread(new ThreadStart(RecvData));
recvThread.Start();
}
// 接收数据
private void RecvData()
{
string s = streamReader.ReadLine();
// 如果没接到服务器退出的消息,则继续接收信息
while (s!=null&&!s.Equals("exit"))
{
listBox1.Items.Add("收到信息:" + s);
s = streamReader.ReadLine();
}
// 收到服务器退出的消息,释放资源
listBox1.Items.Add("服务器关闭");
listBox1.Items.Add("客户端关闭");
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
// streamReader.Close();
// streamWriter.Close();
// networkStream.Close();
// myclient.Close();
ReleaseResouce();
}
private void button2_Click(object sender, EventArgs e)
{
button1.Enabled = true; // 按了停止之后,“连接”按钮可以用,“发送”不能用
button2.Enabled = false;
button3.Enabled = false;
string exitMsg = "exit"; // 要退出时,发送 exit 信息给服务器
streamWriter.WriteLine(exitMsg);
//刷新当前数据流中的数据
streamWriter.Flush();
listBox1.Items.Add("客户端关闭");
ReleaseResouce();
}
private void button3_Click(object sender, EventArgs e)
{
// 启动发送线程
sendThread = new Thread(new ThreadStart(SendData));
sendThread.Start();
}
// 发送数据
private void SendData()
{
// 发送信息不允许为空
if (txtMsg.Text == "")
{
MessageBox.Show("发送的信息不能为空!");
txtMsg.Focus();
return;
}
try
{
//往当前的数据流中写入一行字符串
streamWriter.WriteLine(txtMsg.Text);
//刷新当前数据流中的数据
streamWriter.Flush();
listBox1.Items.Add("发送信息:" + txtMsg.Text);
txtMsg.Text = ""; // 清空
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "ClientClient提示");
}
}
private void Form1_Load(object sender, EventArgs e)
{
// 在未连接服务器前,不能发送信息和停止
button2.Enabled = false;
button3.Enabled = false;
}
// 释放资源
private void ReleaseResouce()
{
networkStream.Close();
streamReader.Close();
streamWriter.Close();
if (sendThread!=null&&sendThread.IsAlive)
{
sendThread.Abort();
}
if (recvThread.IsAlive)
{
recvThread.Abort();
}
if (serverThread.IsAlive)
{
serverThread.Abort();
}
myclient.Close();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// 如果是在连接中,则不允许关闭窗口
if (button1.Enabled == false)
{
MessageBox.Show("请先停止连接!", "ClientClient提示");
e.Cancel = true;
}
}
private void button4_Click(object sender, EventArgs e)
{
// 启动发送线程
st = new Thread(new ThreadStart(SeData));
st.Start();
}
// 发送数据
private void SeData()
{
Random r = new Random();
for (int i = 0; i < 10000; i++)
{
Thread.Sleep(400);
try
{
//往当前的数据流中写入一行字符串
streamWriter.WriteLine(r.Next(80).ToString());
//刷新当前数据流中的数据
streamWriter.Flush();
listBox1.Items.Add("发送信息:" + r.Next(80).ToString());
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "ClientClient提示");
}
}
}
private void button5_Click(object sender, EventArgs e)
{
st.Abort();
}
}
}
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;