C#网络编程之---TCP协议的同步通信(相互发送接收数据)

先把服务端与客户端的连接代码敲出来

服务端
IPAddress ip = new IPAddress(new byte[] { 127, 1, 1, 1 });
TcpListener server = new TcpListener(ip, 8005);
server.Start();//服务端启动侦听
TcpClient client = server.AcceptTcpClient();//接受发起连接对象的同步方法
Console.WriteLine("收到客户端连接请求")//如果没有客户端请求连接,这句话是无法Print out的
客户端
IPAddress ip=IPAddress.Parse("127.1.1.1");
TcpClient client=new TcpClient();
client.Connect(ip,8005);//8005端口号,必须与服务端给定的端口号一致,否则天堂无门

先看看服务端的特殊标记的那句代码

AcceptTcpClient() 这个方法是一个同步方法,在没有接受到连接请求的时候,位于它下面的代码是不会被执行的,也就是线程阻塞在这里,进行不下去了,想出城没有城防长官的批复是不能的,嘿嘿...

连接后,客户端要发送数据给服务端,先贴代码再说

NetworkStream dataStream=client.GetStream();
string msg="服务端亲启!";
byte[] buffer=Encoding.default.getBytes(msg);
stream.write(buffer,0,buffer.length);
//这段代码呈接上面那段客户端代码

NetworkStream 在网络中进行传输的数据流,也就是说传输数据必须写入此流中,才能够互通有无。
首先客户端先获取用于发送信息的流,然后将要发送的信息存入byte[] 数组中(数据必须是byte[] 才能够写入流中),最后就是写入传输的数据流,发送

聪明的你想必已经知道如何在服务端获取数据了
既然客户端费力的把数据包装发给服务端了,那么服务端自然要把包装拆了,得到数据,上代码:

NetworkStream dataStream=client.GetStream();
byte[] buffer=new byte[8192];
int dataSize=dataStream.Read(buffer,0,8192);
Console.write(Encoding.default.GetString(buffer,0,dataSize));
//这段代码呈接上面那段服务端代码

代码一写,我觉得再说多余了,不过还要在说一两句,嘿嘿
Read() 方法需要三个参数,1,存储数据的缓存空间。2,写入数据的起始点就是从存储空间的什么位置开始写入数据。3,就是存储空间的大小。返回写入数据的大小值
Encoding.default.GetString() 参数解析
1,存储数据的缓存空间。2,从什么位置开始接收数据。3,接收多少数据

以上只是再简单不过的数据发送,而且只是客户端发给服务端,只能发一条信息而已,那如果想彼此互发,并且想发多少条信息都可以,怎么办呢

 

首先基于以上的代码,编写一个winform的小程序

界面很简单,要实现的功能就是客户端与服务端互发信息。

感觉还是直接上代码吧

服务端的全部代码如下: 

using hepu.BloodModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

namespace hepu
{
    public partial class Blood5_TCP : Form
    {
        public Blood5_TCP()
        {
            InitializeComponent();
        }
        public delegate void showData(string msg);//委托,防止跨线程的访问控件,引起的安全异常
        private const int bufferSize = 8000;//缓存空间
        private TcpClient client;
        private TcpListener server;
        /// <summary>
        /// 结构体:Ip、端口
        /// </summary>
        struct IpAndPort
        {
            public string Ip;
            public string Port;
        }

        private void Blood5_TCP_Load(object sender, EventArgs e)
        {
           
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (txtIP.Text.Trim() == string.Empty)
            {
                return;
            }
            if (txtPort.Text.Trim() == string.Empty)
            {
                return;
            }

            Thread thread = new Thread(reciveAndListener);
            //如果线程绑定的方法带有参数的话,那么这个参数的类型必须是object类型,所以讲ip,和端口号 写成一个结构体进行传递
            IpAndPort ipHePort = new IpAndPort();
            ipHePort.Ip = txtIP.Text;//服务器IP
            ipHePort.Port = txtPort.Text;//为程序设置端口

            thread.Start((object)ipHePort);
        }
        /// <summary>
        /// 侦听客户端的连接并接收客户端发送的信息
        /// </summary>
        /// <param name="ipAndPort">服务端Ip、侦听端口</param>
        private void reciveAndListener(object ipAndPort)
        {
            IpAndPort ipHePort = (IpAndPort)ipAndPort;

            IPAddress ip = IPAddress.Parse(ipHePort.Ip);
            server = new TcpListener(ip, int.Parse(ipHePort.Port));
            server.Start();//启动监听
            rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "服务端开启侦听....\n");
            //  btnStart.IsEnabled = false;

            //获取连接的客户端对象
            client = server.AcceptTcpClient();
            rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "有客户端请求连接,连接已建立!");//AcceptTcpClient 是同步方法,会阻塞进程,得到连接对象后才会执行这一步  

            //获得流
            NetworkStream reciveStream = client.GetStream();

            #region 循环监听客户端发来的信息

            do
            {
                byte[] buffer = new byte[bufferSize];
                int msgSize;
                try
                {
                    lock (reciveStream)
                    {
                        msgSize = reciveStream.Read(buffer, 0, bufferSize);
                    }
                    if (msgSize == 0)
                        return;
                    string msg = Encoding.Default.GetString(buffer, 0, bufferSize);
                    TextBox1.text=msg;//接收到的信息放到textBox里

                    //rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "\n客户端曰:" + result + "\r\n");
                }
                catch (Exception ex)
                {
                    server.Stop();
                    string aa = ex.Message;
                    MessageBox.Show(aa);
                    rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "\n 出现异常:连接被迫关闭");
                    break;
                }
            } while (true);

            #endregion
        }
 /// <summary>
        /// 将数据包转换成xml格式   提取有效参数
        /// </summary>
        /// <param name="hl7data"></param>
        /// <returns></returns>
        public NewBlood5  FormatXml(string hl7data)
        {
            XmlDocument xmlObject = HL7ToXmlConverter.ConvertToXmlObject(hl7data);
            NewBlood5 blood5 = new NewBlood5();//实体类
            //根据node去获取需要的数据
            blood5.Brcode = HL7ToXmlConverter.GetText(xmlObject, "MSH/MSH.54", 0);
            blood5.WBC = HL7ToXmlConverter.GetText(xmlObject, "MSH/MSH.662", 0);

            return blood5;
        }
    }
}

客户端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace Blood
{
    public partial class TCP : Form
    {
        public TCP()
        {
            InitializeComponent();
        }
        TcpClient client;
        private const int bufferSize = 8000;
        NetworkStream sendStream;
        public delegate void showData(string msg);
        private void TCP_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (txtIP.Text.Trim() == string.Empty)
            {
                return;
            }
            if (txtPort.Text.Trim() == string.Empty)
            {
                return;
            }
            IPAddress ip = IPAddress.Parse(txtIP.Text);
            client = new TcpClient();
            client.Connect(ip, int.Parse(txtPort.Text));
            rtbtxtShowData.AppendText("开始连接服务端....\n");
            rtbtxtShowData.AppendText("已经连接服务端\n");
            //获取用于发送数据的传输流
            sendStream = client.GetStream();
            Thread thread = new Thread(ListenerServer);
            thread.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (client != null)
            {
                //要发送的信息
                if (txtSendMsg.Text.Trim() == string.Empty)
                    return;
                string msg = txtSendMsg.Text.Trim();
                //将信息存入缓存中
                byte[] buffer = Encoding.Default.GetBytes(msg);
                //lock (sendStream)
                //{
                sendStream.Write(buffer, 0, buffer.Length);
                //}
                rtbtxtShowData.AppendText("发送给服务端的数据:" + msg + "\n");
                txtSendMsg.Text = string.Empty;
            }
        }
        private void ListenerServer()
        {
            do
            {
                try
                {
                    int readSize;
                    byte[] buffer = new byte[bufferSize];
                    lock (sendStream)
                    {
                        readSize = sendStream.Read(buffer, 0, bufferSize);
                    }
                    if (readSize == 0)
                        return;
                    rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "服务端曰:" + Encoding.Default.GetString(buffer, 0, readSize) + "\n");

                }
                catch
                {
                    rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "报错");
                }
                //将缓存中的数据写入传输流
            } while (true);
        }
    }
}

 其中用到了,多线程处理还有委托,因为以上我们用到的不管是Connect,还是AcceptTcpClient方法 都是同步方法,会阻塞进程,导致窗口无法自由移动

 rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "服务端开启侦听....\n");

Ok,至此客户端与服务端的数据传递就大功告成了,这只是一个很简单的操作,如果有多个客户端呢?要求异步通信,怎么办?不急,慢慢来,不积跬步无以至千里

如果有什么错的,希望指正。

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我来为您解答关于C#网络编程中Socket Tcp的异步循环接收客户端连接和信息的问题。 在Socket Tcp编程中,异步循环接收客户端连接和信息是一种常见的编程模式,可以有效地提高程序的并发性能和可靠性。下面是一个简单的实现方式: 首先,我们需要创建一个TcpListener对象,并绑定监听的IP地址和端口号: ```csharp TcpListener listener = new TcpListener(IPAddress.Any, 8888); listener.Start(); ``` 然后,我们可以使用异步方式接收客户端的连接请求: ```csharp listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener); ``` 其中,AcceptCallback是一个回调函数,用于处理客户端连接的请求,可以在该函数中创建一个新的TcpClient对象,并使用异步方式接收客户端发送数据。 在AcceptCallback函数中,我们可以使用异步方式接收客户端发送数据: ```csharp TcpClient client = listener.EndAcceptTcpClient(ar); NetworkStream stream = client.GetStream(); byte[] buffer = new byte[4096]; stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), buffer); ``` 其中,ReadCallback是一个回调函数,用于处理客户端发送数据,可以在该函数中解析并处理客户端发送数据。 最后,在ReadCallback函数中,我们可以使用异步方式持续接收客户端发送数据: ```csharp stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), buffer); ``` 以上就是使用异步循环接收客户端连接和信息的基本实现方式。需要注意的是,在实现过程中,我们需要考虑多线程安全和异常处理等问题,以确保程序的稳定性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香煎三文鱼

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值