TCP通讯

这个不是我写的,是在网上找到的,测试了,可以,关了连接一下找不到原文的连接了,之前用网上的例子和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];

        }

    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值