参考网址:http://blog.csdn.net/zhujunxxxxx/article/details/44261497
http://blog.csdn.net/a497785609/article/details/12871301
http://blog.csdn.net/azheng51714/article/details/38709391
一、服务器
界面图:
使用说明:
在断开出输入要监听的端口。信息列表中显示客户端发来的消息。开启是开启监听服务。停止是停止服务。发送按钮是将输入框中的内容发送给客户端。
代码分段介绍:
(1)启动
/// <summary>
/// 点击开启的处理函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
AsyncTCPServer server = new AsyncTCPServer(IPAddress.Any, int.Parse(textBox1.Text));
server.DataReceived += OnDataReceived;
server.Start();
}
这里的AsyncTCPServer 类下面会介绍。这里传入的参数是监听的ip地址,即0.0.0.0,之前我们说过这个字段的意思,你可以任意指定某个ip。第二个参数是端口,就是在输入框中输入的值。
然后这里有一个委托函数,就是当服务端接收数据之后的处理。最后就是Start启动了。
(2)数据接收的委托
在AsyncTCPServer 类中有这样一个成员:
// 数据接收处理委托
public event EventHandler<AsyncEventArgs> DataReceived;
其中EventHandler的是系统的委托定义,如下所示:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
而AsyncEventArgs是我们自己定义的类,处理函数的定义如下:
/// <summary>
/// 数据接收处理函数
/// </summary>
/// <param name="obj"></param>
/// <param name="arg"></param>
TCPClientState state = null;
private void OnDataReceived(object obj, AsyncEventArgs arg)
{
byte[] bytes = new byte[arg.state.DataLength];
Buffer.BlockCopy(arg.state.Buffer, 0, bytes, 0, arg.state.DataLength);
listBox1.Items.Add(Encoding.UTF8.GetString(bytes, 0, bytes.Length));
if(this.state == null)
{
this.state = arg.state; //保存一次客户端。
}
}
这里将接收的数据拷贝到bytes数组中,然后显示在listBox1中,最后保存了当前连接的客户端。其实,我们这里这是涉及到一个客户端,特别简易的一个cs模式,如果是多个客户端,处理起来会更加复杂一些。暂时我们就将一对一的通信。
(3)消息发送函数
/// <summary>
/// 点击发送处理函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
byte[] data = Encoding.UTF8.GetBytes(textBox2.Text);
SendMessage(data);
}
/// <summary>
/// 发送消息处理函数
/// </summary>
/// <param name="bytes"></param>
private void SendMessage(byte[] bytes)
{
if (state.NetworkStream != null)
{
state.NetworkStream.BeginWrite(bytes, 0, bytes.Length, new AsyncCallback(OnWrite), null);
}
}
/// <summary>
/// 回调函数
/// </summary>
/// <param name="iar"></param>
private void OnWrite(IAsyncResult iar)
{
try
{
state.NetworkStream.EndWrite(iar);
}
catch
{
}
}
注释,首先是获取输入框的内容,使用Encoding.UTF8.GetBytes(textBox2.text)的方式获取字节数组,然后调用state.NetworkStream的BeginWrite方法,写入流中去,在OnWrite中调用了EndWrite方法,表示写入结束之后的处理。
(4)AsyncTCPServer的构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="localIPAddress"></param>
/// <param name="listenPort"></param>
public AsyncTCPServer(IPAddress localIPAddress, int listenPort)
{
Address = localIPAddress;
Port = listenPort;
clients = new List<Object>();
listener = new TcpListener(Address, Port);
}
这里有两个参数,一个是ip地址,一个是端口。还有一个就是客户端连接的列表,暂时没有用到。最后一个是监听者listener。
(5)启动方法
/// <summary>
/// 启动连接
/// </summary>
public void Start()
{
if(!IsRunning)
{
IsRunning = true;
listener.Start();
listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), listener);
MessageBox.Show("开启成功!");
}
}
(6)接收客户端连接的回调函数
/// <summary>
/// 接收客户端连接的回调函数
/// </summary>
/// <param name="iar"></param>
private void HandleTcpClientAccepted(IAsyncResult iar)
{
if(IsRunning)
{
TcpClient client = listener.EndAcceptTcpClient(iar);
byte[] buffer = new byte[client.ReceiveBufferSize];
TCPClientState state = new TCPClientState(client, buffer);
lock(clients)
{
clients.Add(state);
RaiseClientConnected(state);
}
NetworkStream stream = state.NetworkStream;
// 开始异步读取数据
stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);
// 监听下一个客户端连接
listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), iar.AsyncState);
}
}
这里就是要注意一个问题,就是当监听到一个客户端的之后,就要构建一个客户端结构,保存到列表中去,然后就开启这个客户端的读数据的操作,以及继续监听下一个客户端连接操作。至于如何区分每个客户端,这个暂时没有考虑。
(7)数据的接收处理函数
/// <summary>
/// 接收数据的回调函数
/// </summary>
/// <param name="iar"></param>
private void HandleDataReceived(IAsyncResult iar)
{
if(IsRunning)
{
TCPClientState state = (TCPClientState)iar.AsyncState;
NetworkStream stream = state.NetworkStream;
int recv = 0;
try
{
recv = stream.EndRead(iar);
}
catch
{
recv = 0;
}
if(recv == 0)
{
lock(clients)
{
clients.Remove(state);
RaiseClientDisconnected(state);
return;
}
}
byte[] buff = new byte[recv];
Buffer.BlockCopy(state.Buffer, 0, buff, 0, recv);
state.DataLength = recv;
// 触发数据收到事件
RaiseDataReceived(state);
// 继续读取数据
stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);
}
}
/// <summary>
/// 委托处理函数
/// </summary>
/// <param name="state"></param>
private void RaiseDataReceived(TCPClientState state)
{
if(DataReceived!=null)
{
DataReceived(this, new AsyncEventArgs(state));
}
}