这个不是我写的,是在网上找到的,测试了,可以,关了连接一下找不到原文的连接了,之前用网上的例子和MSDN里面的,有个问题,可以收发信息,但是不支持异步,会阻塞,页面看起来像卡死了,但是在后台端点可以看到收到或者发出信息了,主要是做服务端,监听的时候这个现象比较明显;放在这里后面复习;
说下我对服务端和客户端的理解;之前一直以为服务端和客户端是固定为某台电脑或者机器,其实,做了后个人认为,当一台电脑收信息时,它相对另外一台发信息的,收信息的就是服务端,发信息的就是客户端;反之,当另外一台收信息时,它就应该当成服务端看,而发信息的应该当做客户端看【个人理解】
//服务端
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace TcpTest2
{
public partial class Form1 : Form
{
bool isExit = false;
System.Collections.ArrayList clientList = new System.Collections.ArrayList();
TcpListener listener;
delegate void SetListBoxCallBack(string str);
SetListBoxCallBack setListCallBack;
delegate void SetRecvBoxCallBack(string str);
SetRecvBoxCallBack setRecvBoxCallBack;
delegate void SetComboBoxCallBack(string str);
SetComboBoxCallBack setComboBoxCallBack;
delegate void RemoveComboBoxCallBack(DataReadWrite drw);
RemoveComboBoxCallBack removeComboBoxCallBack;
ManualResetEvent allDone = new ManualResetEvent(false);//通知一个或多个正在等待的线程已发生事件
Thread t = null;
public Form1()
{
InitializeComponent();
setListCallBack = new SetListBoxCallBack(setListBox);
setRecvBoxCallBack = new SetRecvBoxCallBack(this.setRichBox);
setComboBoxCallBack = new SetComboBoxCallBack(this.setComboBox);
removeComboBoxCallBack = new RemoveComboBoxCallBack(this.removeComboBoxItem);
button2.Enabled = false;
}
private void Form1_Load(object sender, EventArgs e)
{ }
private void setListBox(string str)
{
listBox1.Items.Add(str);
listBox1.SelectedIndex = listBox1.Items.Count - 1;
listBox1.ClearSelected();
}
private void setRichBox(string str)
{
richTextBox1.AppendText(str);
}
private void setComboBox(object obj)
{
comboBox1.Items.Add(obj);
}
private void removeComboBoxItem(DataReadWrite drw)
{
int index = clientList.IndexOf(drw);
comboBox1.Items.Remove(index);
}
private void button1_Click(object sender, EventArgs e)
{
t = new Thread(new ThreadStart(AcceptConn));//新建线程建立侦听
t.Start();
button1.Enabled = false;
button2.Enabled = true;
}
private void AcceptConn()
{
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
//IPAddress[] ips = new IPAddress[];
ips[0] = localAddr;
listener = new TcpListener(localAddr, 9000);
//listener = new TcpListener(ips[0], 9000);
listener.Start();
while (isExit == false)
{
allDone.Reset();//将事件状态设置为非终止状态
AsyncCallback callback = new AsyncCallback(acceptTcpClientCallBack);
listBox1.Invoke(setListCallBack, "开始等待连接");
listener.BeginAcceptTcpClient(callback, listener);//开始一个异步操作,来接受一个传入的连接尝试
allDone.WaitOne();//阻止当前线程,直到allDone.Set()之后继续运行
}
}
/// <summary>
/// 接收到一个请求,此方法运行在异步线程上
/// </summary>
/// <param name="iar"></param>
private void acceptTcpClientCallBack(IAsyncResult iar)
{
allDone.Set();
TcpListener listener = (TcpListener)iar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(iar);//异步接受传入的连接并创建新的TcpClient来处理远程主机通信
listBox1.Invoke(setListCallBack, "已接受客户连接:" + client.Client.RemoteEndPoint);
comboBox1.Invoke(setComboBoxCallBack, client.Client.RemoteEndPoint.ToString());
DataReadWrite drw = new DataReadWrite(client);
clientList.Add(drw);
SendString(drw, "服务器已接受连接");
drw.netStream.BeginRead(drw.read, 0, drw.read.Length, new AsyncCallback(readCallBack), drw);//开始异步读取数据
}
/// <summary>
/// 发送字符串
/// </summary>
/// <param name="drw"></param>
/// <param name="str"></param>
private void SendString(DataReadWrite drw, string str)
{
drw.write = Encoding.UTF8.GetBytes(str + "\r\n");
drw.netStream.BeginWrite(drw.write, 0, drw.write.Length, new AsyncCallback(SendCallBack), drw);//开始向流异步写入数据
drw.netStream.Flush();
listBox1.Invoke(setListCallBack, string.Format("向{0}发送{1}", drw.client.Client.RemoteEndPoint, str));
}
/// <summary>
/// 发送字符串完毕
/// </summary>
/// <param name="iar"></param>
private void SendCallBack(IAsyncResult iar)
{
DataReadWrite drw = (DataReadWrite)iar.AsyncState;
drw.netStream.EndWrite(iar);//异步写入数据结束
}
/// <summary>
/// 接收字符串
/// </summary>
/// <param name="iar"></param>
private void readCallBack(IAsyncResult iar)
{
DataReadWrite drw = (DataReadWrite)iar.AsyncState;
int recv = drw.netStream.EndRead(iar);//异步读取结束
richTextBox1.Invoke(setRecvBoxCallBack, string.Format("来自{0}:{1}\r\n", drw.client.Client.RemoteEndPoint, Encoding.UTF8.GetString(drw.read, 0, recv)));
if (isExit == false)
{
drw.InitReadArr();
drw.netStream.BeginRead(drw.read, 0, drw.read.Length, readCallBack, drw);//无限循环的读取下去
}
}
/// 断开连接,没写代码
private void button2_Click(object sender, EventArgs e)
{ t.Abort(); }
/// <summary>
/// 发送数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
int index = comboBox1.SelectedIndex;
if (index != -1)
{
DataReadWrite drw = (DataReadWrite)clientList[index];
SendString(drw, richTextBox2.Text);
richTextBox2.Clear();
}
else
{ MessageBox.Show("指定接收发送信息的服务端"); }
}
/// <summary>
/// 数据输入输出基础类
/// </summary>
public class DataReadWrite
{
public TcpClient client;
public NetworkStream netStream;
public byte[] read;
public byte[] write;
public DataReadWrite(TcpClient client)
{
this.client = client;
netStream = client.GetStream();//获取用于发送和接受数据的流
read = new byte[client.ReceiveBufferSize];
write = new byte[client.SendBufferSize];
}
public void InitReadArr()
{
read = new byte[client.ReceiveBufferSize];
}
public void InitWriterArr()
{
write = new byte[client.SendBufferSize];
}
}
}
}
//客户端
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace TcpTest
{
public partial class Form1 : Form
{
bool isExit = false;
delegate void SetListBoxCallBack(string str);
SetListBoxCallBack setListCallBack;
delegate void SetRecvBoxCallBack(string str);
SetRecvBoxCallBack setRecvBoxCallBack;
TcpClient client;
NetworkStream netStream;
ManualResetEvent allDone = new ManualResetEvent(false);//通知一个或多个正在等待的线程已发
public Form1()
{
InitializeComponent();
setListCallBack = new SetListBoxCallBack(setListBox);
setRecvBoxCallBack = new SetRecvBoxCallBack(this.setRecvBox);
}
private void Form1_Load(object sender, EventArgs e)
{ }
private void setListBox(string str)
{
listBox1.Items.Add(str);
listBox1.SelectedIndex = listBox1.Items.Count - 1;
listBox1.ClearSelected();
}
private void setRecvBox(string str)
{
richTextBox1.AppendText(str);
}
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
client = new TcpClient(AddressFamily.InterNetwork);
AsyncCallback requestCallBack = new AsyncCallback(this.requestCallBack);//引用在相应异步操作完成时调用的方法
allDone.Reset();//将事件线程设置为非终止状态
client.BeginConnect(IPAddress.Parse(textBox1.Text.Trim()), 9000, requestCallBack, client);
listBox1.Invoke(setListCallBack, string.Format("本地终结点:{0}", client.Client.LocalEndPoint));
listBox1.Invoke(setListCallBack, string.Format("开始与服务器连接"));
allDone.WaitOne();//阻止当前线程,直到allDone.Set()之后继续运行
}
/// <summary>
/// 连接服务器成功
/// </summary>
/// <param name="iar">表示异步操作的状态</param>
private void requestCallBack(IAsyncResult iar)
{
allDone.Set();
client = (TcpClient)iar.AsyncState;
client.EndConnect(iar);
listBox1.Invoke(setListCallBack, string.Format("与服务器{0}连接成功", client.Client.RemoteEndPoint));
netStream = client.GetStream();
DataRead dr = new DataRead(netStream, client.ReceiveBufferSize);//client.ReceiveBufferSize接收缓冲区的大小
netStream.BeginRead(dr.msg, 0, dr.msg.Length, new AsyncCallback(readCallBack), dr);//开始接受数据
}
/// <summary>
/// 接收数据完成
/// </summary>
/// <param name="iar"></param>
private void readCallBack(IAsyncResult iar)
{
DataRead dr = (DataRead)iar.AsyncState;
int recv = dr.netStream.EndRead(iar);
richTextBox2.Invoke(setRecvBoxCallBack, Encoding.UTF8.GetString(dr.msg, 0, recv));
if (isExit == false)
{
dr = new DataRead(netStream, client.ReceiveBufferSize);//此处有些不妥,可参照服务端的做法
netStream.BeginRead(dr.msg, 0, dr.msg.Length, this.readCallBack, dr);//无限的接收下去
}
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
sendString(richTextBox2.Text);
richTextBox2.Clear();
}
/// <summary>
/// 异步发送数据
/// </summary>
/// <param name="str"></param>
private void sendString(string str)
{
byte[] bytesdata = Encoding.UTF8.GetBytes(str + "\r\n");
netStream.BeginWrite(bytesdata, 0, bytesdata.Length, new AsyncCallback(sendCallBack), netStream);
netStream.Flush();
}
/// <summary>
/// 异步发送数据完成
/// </summary>
/// <param name="iar"></param>
private void sendCallBack(IAsyncResult iar)
{
netStream.EndWrite(iar);
}
}
/// <summary>
/// 接收数据基础类
/// </summary>
public class DataRead
{
public NetworkStream netStream;
public byte[] msg;
public DataRead(NetworkStream ns, int buffersize)
{
this.netStream = ns;
this.msg = new byte[buffersize];
}
}
}