C#开发: 通信篇-TCP客户端

摘要:
然后指定发送端口号,信息将发送到李思计算机的网络应用程序B。它分为服务器和客户端。请解释本节教您如何用C#编写TCP客户端程序页。请确保您已经学习了C#开发:通信-串行端口调试助手。在撰写连接程序的正式文件时,将不会重复上述文章中涉及的基本知识:https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket?

前言

关于网络通信:

每一台电脑都有自己的ip地址,每台电脑上的网络应用程序都有自己的通信端口,

张三的电脑(ip:192.168.1.110)上有一个网络应用程序A(通信端口5000),

李四的电脑(ip:192.168.1.220)上有一个网络应用程序B(通信端口8000),

张三给李四发消息,首先你要知道李四的ip地址,向指定的ip(李四ip:192.168.1.220)发信息,

信息就发到了李四的电脑。

再指定一下发送的端口号(通信端口8000),信息就发到了李四电脑的网络应用程序B上。

TCP--一种网络通信方式而已。分为服务器(网络应用程序)和客户端(网络应用程序).

说明

这节教给大家用C#写一个TCP客户端程序

页面

C#开发: 通信篇-TCP客户端第1张

请用户在学习这节之前务必先学完

C#开发: 通信篇-串口调试助手

以上文章涉及到的基础知识不再重复赘述

编写连接程序

官方文档:

https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket?view=netframework-4.8 Socket

https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.beginconnect?view=netframework-4.8 beginconnect

1.定义一个 socket

C#开发: 通信篇-TCP客户端第2张

private Socket MySocket = null;//Socket

如果报错,按照下面步骤添加Socket对应的包(命名空间)

C#开发: 通信篇-TCP客户端第3张

C#开发: 通信篇-TCP客户端第4张

2.编写点击按钮连接/断开程序

C#开发: 通信篇-TCP客户端第5张

C#开发: 通信篇-TCP客户端第6张

        /// <连接按钮点击事件>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(objectsender, EventArgs e)
        {
            if (button1.Text == "连接"){
                //IP地址 和 端口号输入不为空
                if (string.IsNullOrEmpty(textBox1.Text) == false && string.IsNullOrEmpty(textBox2.Text) == false){
                    try{
                        IPAddress ipAddress = IPAddress.Parse(textBox1.Text);//获取IP地址
                        int Port = Convert.ToInt32(textBox2.Text);          //获取端口号
MySocket = newSocket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);

                        //使用 BeginConnect 异步连接
                        MySocket.BeginConnect(ipAddress, Port, newAsyncCallback(ConnectedCallback), MySocket);
                    }
                    catch(Exception){
                        MessageBox.Show("IP地址或端口号错误!", "提示");
                    }
                }
                else{
                    MessageBox.Show("IP地址或端口号错误!", "提示");
                }
            }
            else{
                try{
                    button1.Text = "连接";
                    MySocket.BeginDisconnect(false,null,null);//断开连接
}
                catch(Exception){}
            }
        }
        /// <连接异步回调函数>
        /// 
        /// </summary>
        /// <param name="ar"></param>
        voidConnectedCallback(IAsyncResult ar)
        {
            Socket socket =(Socket)ar.AsyncState;
            try{
                socket.EndConnect(ar);
                
                Invoke((new Action(() =>{
                    textBox3.AppendText("成功连接服务器
");//对话框追加显示数据
                    button1.Text = "断开";
                })));
            }
            catch(Exception e){
                Invoke((new Action(() =>{
                    textBox3.AppendText("连接失败:" + e.ToString());//对话框追加显示数据
})));
            }
        }

3.测试

C#开发: 通信篇-TCP客户端第7张

使用电脑调试助手建立一个TCP服务器

C#开发: 通信篇-TCP客户端第8张

查看一下自己电脑的IP地址

C#开发: 通信篇-TCP客户端第9张

或者点击控制面板,按照以下路径进入

C#开发: 通信篇-TCP客户端第10张

C#开发: 通信篇-TCP客户端第11张

C#开发: 通信篇-TCP客户端第12张

C#开发: 通信篇-TCP客户端第13张

C#开发: 通信篇-TCP客户端第14张

C#开发: 通信篇-TCP客户端第15张

关于同步和异步

就对于上面的连接而言,其实还有一个连接函数

C#开发: 通信篇-TCP客户端第16张

首先大家应该知道,有些通信需要点时间才能完成

上面的 Connect函数执行以后就一直等待,直至连接成功才接着往下执行

Connect 函数就是个同步函数.

这样会造成程序卡机!如果卡机时间过长,程序就会报错误

一般把同步函数放到任务里面去执行,这样就避免了卡机

异步函数也是底层封装的函数,当执行完以后,不会停在那里

而是接着往下执行,有相应的事件以后才会跳转到回调函数里面去.

这是异步的好处

接收数据

https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.beginreceive?view=netframework-4.8

public IAsyncResult BeginReceive (byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags, AsyncCallback callback, object state);

C#开发: 通信篇-TCP客户端第17张

1.定义一个用于缓存数据的数组

C#开发: 通信篇-TCP客户端第18张

        public const int TCPBufferSize = 1460;//缓存的最大数据个数
        public byte[] TCPBuffer = new byte[TCPBufferSize];//缓存数据的数组

2.在连接回调函数里面调用异步接收函数

C#开发: 通信篇-TCP客户端第19张

                //设置异步读取数据,接收的数据缓存到TCPBuffer,接收完成跳转ReadCallback函数
                socket.BeginReceive(TCPBuffer, 0, TCPBufferSize, 0,new AsyncCallback(ReadCallback), socket);

3.接收到数据回调函数

C#开发: 通信篇-TCP客户端第20张

        /// <接收到数据回调函数>
        /// 
        /// </summary>
        /// <param name="ar"></param>
        voidReadCallback(IAsyncResult ar)
        {
            Socket socket = (Socket)ar.AsyncState;//获取链接的Socket
            int CanReadLen = socket.EndReceive(ar);//结束异步读取回调,获取读取的数据个数

            if (CanReadLen > 0)
            {
                string str = Encoding.Default.GetString(TCPBuffer,0, CanReadLen);//Byte值根据ASCII码表转为 String
                Invoke((new Action(() => //C# 3.0以后代替委托的新方法
{
                    textBox3.AppendText(str);//对话框追加显示数据
})));

                //设置异步读取数据,接收的数据缓存到TCPBuffer,接收完成跳转ReadCallback函数
                socket.BeginReceive(TCPBuffer,0, TCPBufferSize, 0, newAsyncCallback(ReadCallback), socket);
            }
            else//异常
{
                Invoke((new Action(() => //C# 3.0以后代替委托的新方法
{
                    button1.Text = "连接";
                    textBox3.AppendText("异常断开
");//对话框追加显示数据
})));
                try{
                    MySocket.BeginDisconnect(false, null, null);//断开连接
}
                catch(Exception) { }
            }
        }

注意

string str = Encoding.Default.GetString(TCPBuffer,0, CanReadLen);//Byte值根据ASCII码表转为 String

不能直接 Encoding.Default.GetString(TCPBuffer)

因为实际接收的数据个数为CanReadLen

4.测试

C#开发: 通信篇-TCP客户端第21张

C#开发: 通信篇-TCP客户端第22张

16进制显示数据

1.关于16进制显示和前面的串口上位机显示16进制数据是一样的道理

https://www.cnblogs.com/yangfengwu/p/12382103.html

/// <字节数组转16进制字符串>
        /// <param name="bytes"></param>
        /// <returns>String 16进制显示形式</returns>
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = "";
            try{
                if (bytes != null)
                {
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        returnStr += bytes[i].ToString("X2");
                        returnStr += " ";//两个16进制用空格隔开,方便看数据
}
                }
                returnreturnStr;
            }
            catch(Exception)
            {
                returnreturnStr;
            }
        }

不过需要改一下,需要传进来数据长度,不能使用bytes.Length

C#开发: 通信篇-TCP客户端第23张

2.添加处理

C#开发: 通信篇-TCP客户端第24张

                Invoke((new Action(() => //C# 3.0以后代替委托的新方法
{
                    if (checkBox1.Checked)//16进制显示
{
                        textBox3.AppendText(byteToHexStr(TCPBuffer, CanReadLen));//对话框追加显示数据
}
                    else{
                        textBox3.AppendText(Encoding.Default.GetString(TCPBuffer, 0, CanReadLen));//对话框追加显示数据
}
                })));

3.测试

C#开发: 通信篇-TCP客户端第25张

C#开发: 通信篇-TCP客户端第26张

清除接收数据

C#开发: 通信篇-TCP客户端第27张

textBox3.Clear();

发送数据

C#开发: 通信篇-TCP客户端第28张

1.点击发送按钮发送数据

C#开发: 通信篇-TCP客户端第29张

            String Str = textBox4.Text.ToString();//获取发送文本框里面的数据
            try{
                if (Str.Length > 0)
                {
                    byte[] byteArray = Encoding.Default.GetBytes(Str);//Str 转为 Byte值
                    MySocket.BeginSend(byteArray,0, byteArray.Length,0,null,null); //发送数据
}
            }
            catch (Exception) { }

2.测试

C#开发: 通信篇-TCP客户端第30张

C#开发: 通信篇-TCP客户端第31张

3.发送16进制数据

3.1. 用户参考:

https://www.cnblogs.com/yangfengwu/p/12382103.html

3.2转换程序如下

/// <字符串转16进制格式,不够自动前面补零>
        /// 
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] strToToHexByte(String hexString)
        {
            inti;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
{
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
                try{
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
                }
                catch{
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                returnreturnBytes;
            }
            else{
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try{
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch{
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                returnreturnBytes;
            }
        }

4.编写发送16进制数据程序

C#开发: 通信篇-TCP客户端第32张

                    if (checkBox2.Checked)//选择16进制发送
{
                        byte[] byteHex =strToToHexByte(Str);
                        MySocket.BeginSend(byteHex, 0, byteHex.Length, 0, null, null); //发送数据
}
                    else{
                        byte[] byteArray = Encoding.Default.GetBytes(Str);//Str 转为 Byte值
                        MySocket.BeginSend(byteArray, 0, byteArray.Length, 0, null, null); //发送数据
                    }

5.测试

C#开发: 通信篇-TCP客户端第33张

C#开发: 通信篇-TCP客户端第34张

6,清除发送

C#开发: 通信篇-TCP客户端第35张

textBox4.Clear();

免责声明:文章转载自《C#开发: 通信篇-TCP客户端》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇QT 线程内定时器QTimer无效问题解决方案Windows Server 2008 R2入门之用户管理下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

PLSQL配置怎么连ORACLE

如果是windows的话,在服务里面就可以查服务要启动,监听也要启动!可以用lsnrctl命令查看监听! 首先你需要在我的电脑的属性里,找到环境变量,配置系统下面的path,看看里面指向的是哪里(我的电脑里就有oracle的多个版本)而且要在你的oracle的X:oracleproduct10.2.0db_1 etworkADMIN nsnames.ora...

W5500问题集锦(持续更新中)

在”WIZnet杯”以太网技术竞赛中,有非常多參赛者在使用中对W5500有各种各样的疑问,对于这款WIZnet新推出的以太网芯片,使用中大家是不是也一样存在下面问题呢?来看一看: 1. W5500不支持自己主动极性变换,有点失望…… 答: 事实上,仅仅要对方支持极性变换就能够实现,如今的设备不支持极性变换的非常少的。 你要是碰到个别老设备连不上,再...

Java AES加密解密工具 -- GUI 、在线传输文件

原理 对于任意长度的明文,AES首先对其进行分组,每组的长度为128位。分组之后将分别对每个128位的明文分组进行加密。 对于每个128位长度的明文分组的加密过程如下: (1)将128位AES明文分组放入状态矩阵中。 (2)AddRoundKey变换:对状态矩阵进行AddRoundKey变换,与膨胀后的密钥进行异或操作(密钥膨胀将在实验原理七中详细讨论)。...

Ubuntu12.10安装多个Mysql5.5实例(一)

本篇记录如何在一台机器上安装多个mysql 实例(这样做的好处暂不讨论,可以google) 1.安装mysql  1)创建必要的用户,用户组(涉及到安全,不要用root安装,且mysql不允许直接sudo启动mysqld,必须指定--user=mysql) 1 sudo groupadd mysql 2 sudo useradd -r -g mysql m...

DLNA介绍(包含UPnP,2011/6/20 更新)

这部分的内容大多来源于网络及官方文档,依照自己的翻译理解整理所成。东西比較多,从头慢慢看还是能够懂个大概的。 文件夹: 一、DNLA的建立 二、DLNA的成员 三、DLNA标准的制定 四、DLNA的设备 五、DLNA的架构 六、云时代的数字家庭(待填坑) 扩展阅读I: UPnP的工作过程------------DLNA基础协议框架 扩展阅读II UPnP...

安卓手机屏幕投射到电脑以及一台电脑控制多台手机技术原理浅析

奥创软件研究院推出的奥创群控让越来越多的人了解到了电脑控制手机的操作。自奥创软件研究院首家发布电脑批量控制手机的解决方案以来,有很多人开始探讨电脑控制手机技术在实际工作中的应用。 由于市场太大,仅靠奥创软件研究院一家也是做不过来的,现在将手机屏幕投射到到电脑的技术原理,以及一台电脑批量控制多台手机的技术(即所谓的手机反响控制)简单的给大家介绍下,在此抛砖引...