TCP通信(三)——数据读写

参考网址: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));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值