【C#网络编程系列】专题五:TCP编程

前言 

前面专题的例子都是基于应用层上的HTTP协议的介绍, 现在本专题来介绍下传输层协议——TCP协议,主要介绍下TCP协议的工作过程和基于TCP协议的一个简单的通信程序,下面就开始本专题的正文了。

一、TCP的工作过程

       首先TCP是一种面向连接的,可靠的,基于字节流的传输层通信协议。TCP的工作过程可以分为三个阶段:一、连接的建立;  二、传输数据; 三、断开连接,下面就对这三个过程分别介绍下:

1.1 连接的建立

      TCP的连接建立就像打电话一样, 我们打电话时,拨一个号码的号码并不是立即就可以接通的,期间会有一个“嘟 嘟”的呼叫过程, 这就好比是TCP协议的连接的建立阶段。当我们用TCP编写的程序,必须先建立TCP连接。TCP协议的连接建立通过三次握手来完成的,下面是在网上找的一张TCP三次握手的图片:

下面就对这三次握手简单的介绍:

第一次握手:建立连接时,客户端发送SYN包(seq=x)到服务器,并进入SYN_Send状态,等待服务器确认

第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=x+1),同时自己也发送一个SYN包(SEQ=y),即SYN+ACK包,此时服务器进入SYN_Recv状态

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=y+1),此包发送完毕,客户端和服务器进入Established(建立)状态,完成三次握手。

简单理解三次握手就是发送一个检验包给对方然后互相确认,双方都接到确认的一个信号时,这时候双方就建立了连接(就像我们打电话时,如果没人说话时就会说下 “喂”,说这句“喂” 也就是希望得到对方的一个确认,虽然这里双方已经建立了连接的,这里只是更形象的说明下三次握手的过程)。

1.2 传输数据

      双方建立了连接,即在双方建立了一个通信通道(就像一座桥一样,在两端建立了一个通路,用桥来比喻通信通道主要是因为最近有一则新闻:哈尔滨阳明滩大桥坍塌事件),建立连接之后,当然是传输我们需要传输的数据到对方的,这里就开始简单介绍下传输数据的过程。

      利用TCP传输数据时,数据是以字节流的形式进行传输,客户端与服务器端建立连接后,发送方需要先将发送的数据转换为字节流,然后将其发送给对方,发送数据时,可以通过程序不断地将数据流陆续写入TCP的发送缓冲中,然后TCP自动从发送缓冲中提取一定量的数据,将其组成TCP报文段发送到IP层,再通过IP层(也就是网络层)之下的网络接口发送出去;接受端从IP层接收到TCP报文段后,将其暂时保存在接受缓冲中,然后我们通过程序依次读取接受缓冲中的数据,从而达到相互通信的目的(简单的说就发送方把数据转换为数据流,再把数据流存储在发送缓冲中,然后传输层低层的协议从发送缓冲中读取数据把数据发送出去,然后接收端从底层接受到数据把数据存储在接收端的缓冲中,然后我们写的程序只是从缓冲中依次读取数据,然后显示出来,在客户端我们写代码做的事情是把数据写入Write写入发送端的缓冲中,然后服务器端(接收端)用Read方法在自己的缓冲中读取数据,用一句话概括,TCP的传输就是对数据的写——读操作)括号中的内容只是我个人理解,因为这样我感觉理解起来比较容易,对于刚开始接触TCP的朋友可以这样理解,然后再一句句话去扩展。

1.3 断开连接

发送完数据之后,最后就是断开连接了,下面是网上断开的连接的一张图片(断开一个连接需要经过四次握手):

     TCP的工作过程就分为上面三个过程,TCP编程是作为上层应用编程的基础,就像之前专题中基于HTTP协议的Web服务器,Web浏览器,其传输层都用的是TCP协议进行传输的,还有基于FTP(文件传输协议),IMAP(交互式邮件存取协议) POP3(邮局协议的第3个版本) 和SMTP(简单邮件传输协议)的网络应用其传输层都用的是TCP协议,而不是UDP等其他传输层协议。

二、基于TCP协议的简单通信程序

这里简单实现了一个客户端与服务器间的通信程序,核心代码为:

服务端开始监听的方法:

  /// <summary>
        /// 开始监听
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStartMonitor_Click(object sender, EventArgs e)
        {
            _tcpListener = new TcpListener(_ipAddress, _port);
            _tcpListener.Start();
            //启动一个线程来接受请求
            Thread acceptThread = new Thread(AcceptClientConnect);
            acceptThread.Start();
        }
        /// <summary>
        /// 接受请求
        /// </summary>
        private void AcceptClientConnect()
        {
            statusInfo.Invoke(_showStatusCallback, "正在监听...");
            Thread.Sleep(1000);
            try
            {
                statusInfo.Invoke(_showStatusCallback, "等待连接...");
                _tcpClient = _tcpListener.AcceptTcpClient();
                if (_tcpListener != null)
                {
                    statusInfo.Invoke(_showStatusCallback, "接收到连接");
                    _netStream = _tcpClient.GetStream();
                    _reader = new BinaryReader(_netStream);
                    _writer = new BinaryWriter(_netStream);
                }
            }
            catch
            {
                statusInfo.Invoke(_showStatusCallback, "停止监听");
                Thread.Sleep(1000);
                statusInfo.Invoke(_showStatusCallback, "就绪");
            }

        }

客户端连接服务端方法:

 /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConnect_Click(object sender, EventArgs e)
        {
            Thread connectThread = new Thread(ConnectToServer);
            connectThread.Start();
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        private void ConnectToServer()
        {
            try
            {
                statusStripInfo.Invoke(_showStatusCallback, "正在连接...");
                if (string.IsNullOrEmpty(txtIPAddress.Text) || string.IsNullOrEmpty(txtPort.Text))
                {
                    MessageBox.Show("请输入服务器地址和端口号!");
                    return;
                }
                IPAddress ip = IPAddress.Parse(txtIPAddress.Text);
                _tcpClient = new TcpClient();
                _tcpClient.Connect(ip, int.Parse(txtPort.Text));

                //延时操作
                Thread.Sleep(1000);
                if (_tcpClient != null)
                {
                    statusStripInfo.Invoke(_showStatusCallback, "连接成功");
                    _netStream = _tcpClient.GetStream();
                    _reader = new BinaryReader(_netStream);
                    _writer = new BinaryWriter(_netStream);
                }
            }
            catch
            {
                statusStripInfo.Invoke(_showStatusCallback, "连接失败");
                Thread.Sleep(1000);
                statusStripInfo.Invoke(_showStatusCallback, "就绪");
            }
        }

客户端发送消息方法:

/// <summary>
        /// 发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            Thread sendThread = new Thread(SendMessage);
            sendThread.Start(txtMessage.Text);
        }
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="str">消息</param>
        private void SendMessage(object message)
        {
            try
            {
                statusStripInfo.Invoke(_showStatusCallback, "正在发送...");
                _writer.Write(message.ToString());
                Thread.Sleep(5000);
                _writer.Flush();
                statusStripInfo.Invoke(_showStatusCallback, "完毕");

                txtMessage.Invoke(_cleanMessagCallback);
                lstMessage.Invoke(_showMessageCallback, message.ToString());
            }
            catch
            {
                if (_reader != null)
                {
                    _reader.Close();
                }
                if (_writer != null)
                {
                    _writer.Close();
                }
                if (_tcpClient != null)
                {
                    _tcpClient.Close();
                }
                statusStripInfo.Invoke(_showStatusCallback, "断开了连接");
            }
        }

效果图:



源码下载:点击打开链接

原文地址:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值