Winfrom下的socket TCP基础通信

大家好,我是你们的好朋友程序员:铭文

先简单的说下:好久没写通信了最近几年一直在写一些业务的接口程序。处理一些数据业务,但是根据工作需要:我现
在要写一个和下位机做这个时时通信的这样一个程序,目的主要是简历这个连接进行和下位机的交互,数据的传递:

Socket基础:

其实我的理解就是:Socket就是一个最最基础的通信而已。它是通过服务的端口来进行连接。连接互联网的机器都有自己的ip,也就是我们自己的服务器ip但是我们大家都连接到 Internet网 以后,我们就是可以通过这个socket 来进行通信。我们程序猿也都知道:网络通信的工作的7层吧:

1. 最基础的物理层:有 线路,光纤网线这些东西。
2. 数据链路层: 这就是我们内网的以太网。就是一个代表。
3. 网络传输层:这一层比较复杂:数据链路层的数据在这一层被转换为数据包,数据包这些就是分段组合。然后通过网络设备传送到另外一台网络设备的:TCP/IP,和地址解析等等感兴趣的可以自己去搜索下,
4. 运输层: 这就就包含我们这次要实现的 :TCP和UDP
5. 会话层: 这一层非常简单:用我们前后端分离的开发模式说就是:你前端拿了后端的api接口 return的数据。我来进行数据的渲染哈哈;还有 有2个页面之间的session会话对象,
6 表示层:
,比如我们经常使用的QQ就是socket 通信的一种:
在这里插入图片描述
打开QQ的设置就可以看到,这里我们可以看到服务器类型这块分为2个:UDP,TCP
7 应用层: 这个就代表的是应用的本身了。比如qq。通过应用程序的通讯服务的就是我们最容易理解的应用层。

UDP的介绍与应用:

我这边简单的说下:
udp就是用户数据报告交互协议,记住的关键单就是:不是面向连接的。不可靠的数据传输,udp的可靠性比较差。它可以把应用程序传给服务层(ip)的数据发送出去,但是不能保证到达。就是我们经常会出现的。丢数据,丢包,数据不稳定,udp是会经常出现的、
举一个简单的事例:
我们经常使用qq电话视频。这个时候如果信号差的时候经常会出现卡顿。但是连接还是有的,但是视频信号用的就是udp,我做的就是可以保证,视频信号高效率的发出,至于你接收端的接收等等不在我考虑的范围内。就是我们“ping” 命令来测试两台主机之间 tcp/ip 通信,其实“ping”命令的原理就是向服务主机发送UDP数据包,然后服务主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。就是这么简单,

TCP的介绍与应用 TCP/IP(Transmission Control Protocol/Internet Protocol 传输控制协议/网间协议) :

这个需要着重说下,因为目前我们使用的也是这个:
传输控制协议 tcp:可以2个主机之间交互反馈。也就是我们协议之间理解的一种“心跳”互动,交互的概念。实现的比如,我们做的交互,一段时间没有回复,定义的规则下我可以再次的发送消息。等另外还可以做到负责恢复,这个我没用过,我也是看书上写的。
网间协议 IP:可以进行传输的数据包的分割组装。我们项目中就出现了一个这个的问题:我们的环境是写了一个python 来读取别人系统的数据,然后把数据通过咱们现在说的这个tcp传输到下位机上面。下位机然后再把数据传输到。winfrom上面就是我们上位机的一个程序上面,我主要负责的就是下位机数据的处理,但是这个时候,下位机给我提交的数据就出现了一个问题,经常丢数据,丢包,丢前面或者丢后面,后来证实了。他的那个下位机的单片机传输的数据只能包含2k之内,不然经常丢数据,这个时候就要通过网间协议来,把数据进行分割。重新储存了。
tcp的特点和定义
tcp和udp正好相反:是面向连接、可靠的字节流服务
不废话了上源码:(这是一个winfrom的程序)
客户端代码:

public partial class frmMainSender : Form
    {
        private Socket _socketSend = null;
        private Thread _watchThread = null;
        private Thread _heartBeatThread = null;
        private tm.Timer _timer = null;

        public frmMainSender()
        {
            InitializeComponent();
            this.Load += FrmMainSender_Load;
        }

        private void FrmMainSender_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(txtIP.Text) || string.IsNullOrEmpty(txtPort.Text))
                {
                    MessageBox.Show("IP及端口不可空!");
                    return;
                }
                //IPAddress 类包含计算机在网络上的 IP 地址,它主要提供网际协议地址(IP)
                IPAddress ipAdd = IPAddress.Parse(txtIP.Text);
                _socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //ReceiveTimeout 属性确定Read方法在能够接受数据之前保持阻塞状态的时间量
                _socketSend.ReceiveTimeout = 10000;
                //超时时间量
                _socketSend.SendTimeout = 10000;
                _socketSend.Connect(new IPEndPoint(ipAdd, Int32.Parse(txtPort.Text)));

                WriteLog("连接服务器成功!");
                btnStartServer.Enabled = false;

                _watchThread = new Thread(Received);
                _watchThread.IsBackground = true;
                _watchThread.Start();

                _heartBeatThread = new Thread(HeartBeat);
                _heartBeatThread.IsBackground = true;
                _heartBeatThread.Start();
            }
            catch (Exception)
            {
            }
        }

        private void Received()
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[1024 * 1024 * 3];
                    int length = _socketSend.Receive(buffer);
                    if (length == 0)
                    {
                        break;
                    }
                    string str = Encoding.UTF8.GetString(buffer, 0, length);

                    if (str.ToLower() == "heartbeat")
                    {
                        WriteLog("客户端---接收--检测心跳包!");
                        continue;
                    }
                    else if (str.ToLower() == "1")
                    {
                        WriteLog("接收端接收成功!");
                        continue;
                    }
                    txtReceiveData.Text = str;
                }
                catch (Exception)
                {
                }
            }
        }


        private void HeartBeat()
        {
            _timer = new tm.Timer(3000);
            _timer.Elapsed += _timer_Elapsed;
            _timer.Start();
        }


        private void _timer_Elapsed(object sender, tm.ElapsedEventArgs e)
        {
            try
            {
                WriteLog("客户端---发送---检测心跳包!");
                byte[] buffer = Encoding.UTF8.GetBytes("HeartBeat");
                _socketSend.Send(buffer);
            }
            catch (Exception)
            {

            }

        }

        private void btnStopServer_Click(object sender, EventArgs e)
        {
            if (_socketSend == null) return;
            if (!_socketSend.Connected) return;

            try
            {
                _heartBeatThread.Abort();
                _timer.Stop();
                _timer = null;
                _socketSend.Shutdown(SocketShutdown.Both);


            }
            catch (Exception)
            {
            }

            try
            {
                _socketSend.Close();
            }
            catch (Exception)
            {
            }

            btnStartServer.Enabled = true;
            WriteLog("服务已关闭!");
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                byte[] buffer = Encoding.UTF8.GetBytes(txtBase64Data.Text);
                _socketSend.Send(buffer);
                WriteLog("已发送数据!");
            }
            catch (Exception)
            {
            }
        }

        private void btnBase64_Click(object sender, EventArgs e)
        {
            byte[] bytes = Encoding.Default.GetBytes(txtReceiveData.Text);
            txtBase64Data.Text = Convert.ToBase64String(bytes);
        }

        private void WriteLog(string message)
        {
            txtLogs.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + "----" + message + "\r\n");
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txtReceiveData.Text = "";
            txtBase64Data.Text = "";
        }

        private void btnClearLog_Click(object sender, EventArgs e)
        {
            txtLogs.Clear();
        }
    }

服务器端代码:

public partial class frmMainReceiver : Form
    {
        private Socket _socketSend = null;
        //定义一个集合,存储客户端信息
        static Dictionary<string, Socket> clientConnectionItems = new Dictionary<string, Socket> { };
        private tm.Timer _timer = null;
        private Thread _heartBeatThread = null;
        private Thread _watchThread = null;
        static Socket _socketWatch = null;

        public frmMainReceiver()
        {
            InitializeComponent();
            this.Load += FrmMainReceiver_Load;
        }

        private void FrmMainReceiver_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(txtIP.Text) || string.IsNullOrEmpty(txtPort.Text))
                {
                    MessageBox.Show("IP及端口不可空!");
                    return;
                }

                IPAddress ipAdd = IPAddress.Any;
                //new Socket 实例
                _socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //绑定下
                _socketWatch.Bind(new IPEndPoint(ipAdd, Int32.Parse(txtPort.Text)));
                //套接口并监听申请的连接
                _socketWatch.Listen(100);

                WriteLog("服务已启动!");

                btnStartServer.Enabled = false;
				//线程
                _watchThread = new Thread(Listen);
                _watchThread.IsBackground = true;
                _watchThread.Start(_socketWatch);

                _heartBeatThread = new Thread(HeartBeat);
                _heartBeatThread.IsBackground = true;
                _heartBeatThread.Start();
            }
            catch (Exception ec) { }
        }

        private void HeartBeat()
        {
            _timer = new tm.Timer(5000);
            _timer.Elapsed += _timer_Elapsed;
            _timer.Start();
        }


        private void _timer_Elapsed(object sender, tm.ElapsedEventArgs e)
        {
            string[] keys = new string[clientConnectionItems.Keys.Count];
            clientConnectionItems.Keys.CopyTo(keys, 0);

            foreach (string key in keys)
            {
                Socket socket = clientConnectionItems[key];
                if (socket.Poll(10000, SelectMode.SelectRead))
                {
                    WriteLog(key + "---已断开连接!");
                    clientConnectionItems.Remove(key);
                    continue;
                }
                byte[] buffer = Encoding.UTF8.GetBytes("HeartBeat");
                socket.Send(buffer);


                WriteLog("接收端--向" + key + "-发送---检测心跳包!");
            }
        }

        private void Listen(object o)
        {
            try
            {
                Socket socketWatch = o as Socket;
                while (true)
                {
                    _socketSend = socketWatch.Accept();//等待接收客户端连接

                    //客户端网络结点号  
                    string remoteEndPoint = _socketSend.RemoteEndPoint.ToString();
                    clientConnectionItems.Add(remoteEndPoint, _socketSend);

                    WriteLog(remoteEndPoint + "连接成功!");

                    Thread thread = new Thread(ReceiveData);
                    thread.IsBackground = true;
                    thread.Start(_socketSend);
                }
            }
            catch (Exception e)
            {

            }

        }

        private void ReceiveData(object o)
        {
            try
            {
                Socket socketClient = o as Socket;
                while (true)
                {
                    byte[] buffer = new byte[1024 * 1024 * 3];
                    int length = socketClient.Receive(buffer);
                    if (length == 0)
                    {                    
                        continue;
                    }

                    string strMsg = Encoding.UTF8.GetString(buffer, 0, length);// 将接受到的字节数据转化成字符串;

                    txtReceiveData.Text = strMsg;

                    if (strMsg.ToLower() == ("heartbeat"))
                    {
                        WriteLog("接收端---接收来自" + socketClient.RemoteEndPoint.ToString() + "---检测心跳包!");
                        byte[] bufferBack = Encoding.UTF8.GetBytes("HeartBeat");
                        socketClient.Send(bufferBack);
                        continue;
                    }                   

                    byte[] outputb = Convert.FromBase64String(txtReceiveData.Text.Replace(' ', '+'));
                    txtNoBase64Data.Text = Encoding.Default.GetString(outputb);

                    WriteLog("接收端---接收到数据!");
                    //接收完数据后向客户端发送数据接收成功标志
                    socketClient.Send(Encoding.UTF8.GetBytes("1"));
                }
            }
            catch (Exception e)
            {
            }
        }

        private void WriteLog(string message)
        {
            txtLogs.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + "----" + message + "\r\n");
        }

        private void btnStopServer_Click(object sender, EventArgs e)
        {
            if (_socketSend == null) return;
            if (!_socketSend.Connected) return;

            try
            {
                _timer.Stop();
                _timer = null;
                _heartBeatThread.Abort();
                _watchThread.Abort();
                _socketSend.Shutdown(SocketShutdown.Both);
                _socketWatch.Shutdown(SocketShutdown.Both);
                clientConnectionItems.Clear();
            }
            catch (Exception)
            {
            }

            try
            {
                _socketSend.Close();
                _socketWatch.Close();
            }
            catch (Exception)
            {
            }

            btnStartServer.Enabled = true;
            WriteLog("服务已关闭!");
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txtReceiveData.Text = "";
            txtNoBase64Data.Text = "";
        }

        private void btnClearLog_Click(object sender, EventArgs e)
        {
            txtLogs.Clear();
        }
    }

以上的就是 socket tcp 的双方的交互验证
希望大家又不懂的地方可以留言。我们互相交流,有欠妥的地方,也希望大家指出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一个武术猴子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值