C# TCP通讯(Sockets)

本文详细介绍了C#中TCP通讯的实现,包括TCP协议基础、.NET平台下的TCP工作模式,以及TCP服务端和客户端的编程思路和示例代码。通过三次握手建立连接,利用Socket进行数据传输,适合初学者掌握TCP通讯技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

最近在学习TCP通讯方面知识,网上看了很多资料,很多零零散散,在这里做一个总结汇总,也是对自己最近学习的一个总结。.

什么是TCP1

TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer),TCP协议能够检测和恢复IP层提供的主机到主机的信道中可能发生的报文丢失、重复以及其他错误。由于TCP协议是一种面向连接协议:在使用它进行通信之前,两个应用程序之间首先要建立一个TCP连接。

1.TCP概述
  通信双方建立了TCP连接后,双方就可以相互发送数据了。TCP负责把用户数据(字节流)按照一定格式和长度组成多个数据报进行发送,然后在接到数据报之后分解按顺序重新组装和恢复用户数据。利用TCP传输数据时,数据时以字节的形式进行传输的。客户端和服务端建立连接后,发送数据方需要先将数据转换为字节流,然后将字节流发送到对方。TCP协议主要有以下特点:

	1.是面向连接的传输层协议
	2.每个TCP连接只能有两个端点,且只能一对一通信
	3.通过TCP连接传送数据能够保证报文的完整和准确性
	4.数据只能够以字节流的形式传输
	5.传输的数据无消息边界

2.在.NET平台TCP应用的工作模式 
  在.NET平台下开发TCP应用程序,框架提供两种工作方式,①同步工作方式 ②异步工作方式。这里所说的同步工作方式和异步工作方式和线程间的同步并不是一个概念。线程间的同步指的是不同线程或其他共享资源具有先后关联的关系;而同步TCP和异步TCP指的是TCP编程中采用的两种不同的工作方式,即:从执行到方式、接收或监听语句时,程序是否继续往下执行,继续执行的就是异步TCP,如果程序阻塞那就是同步TCP。

3.通讯(Socket)

  1. socket相关概念:socket的英文原义是"孔"或"插座"。作为进程通信机制,去后一种意思。通常也称作套接字,用于描述IP地址和端口,是一个通信链的句柄(其实就是两个程序通信用的。)这里先通俗的解释一下什么是Socket,举一个例子如果A同学要和B同学进行通话,而进行通话的最基本的三个条件就是A和B同学都要有手机,电话号码,和进行通话的软件,如果A同学要想让B同学明白自己说什么,那么A,B同学还要说这对方都听得懂的语言。而两个应用程序要进行通话,就需要通过(Socket),在这里Socket就是电话,手号码就是IP地址,这通话的软件就是端口,语言则就是协议。
  2. 在Internet上有很多这样的主机,这些主机一半运行了多个服务软件,同时提供几种服务。每种服务都打开了一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序
  3. 列如 http使用80端口,ftp使用21端口,smtp25端口
  4. 有两种类型:
    流式Socket(STREAM):针对于面向连接的TCO服务应用,安全但是效率低;
    数据报式Socket(DATAGRAM):是一种无连接的Socket,对应于无连接的UDP服务应用,不安全(丢失,顺序混乱,在接收端要分析重排及要求重发)但效率高。

客户端连接服务器:
1.服务器的IP地址
2.应用程序IP地址(端口号每一个应用程序系统都会分配一个端口号)
3.服务器Socket(负责监听应用程序的IP地址和端口号,看看是否有请求连,当有客户端连接过来的时候创建一个负责跟客户端通信的Socke,这里不要混淆,一个就是负责监听,一个就是负责通信因此服务端最少有两个Socker)
4.客户端Socket连接服务端指定端口(负责接受和发送服务端消息)

4.三次握手
什么是三次握手
ACK:TCP报头的控制位之一,表示确认号是否有效。只有当ACK=1时,确认号才有效,当ACK=0时,确认号无效,这时会要求重传数据,保证数据的完整性。

确认号:用它来告诉发送端发送过来的序列号之前的数据段都收到了。比如,确认号为X,则表示前X-1个数据段都收到了。

SYN:同步序列号,TCP建立连接时将这个位置1。

FIN:发送端完成发送任务位,当TCP完成数据传输需要断开时,提出断开连接的一方将这位置1。

TCP建立连接三次握手过程

1、主机A通过向主机B发送一个含有同步序列号的标志位的数据段给主机B ,向主机B 请求建立连接,通过这个数据段,主机A告诉主机B 两件事:我想要和你通信;你可以用哪个序列号作为起始数据段来回应我。

2、主机B 收到主机A的请求后,用一个带有确认应答(ACK)和同步序列号(SYN)标志位的数据段响应主机A,也告诉主机A两件事:我已经收到你的请求了,你可以传输数据了;你要用哪个序列号作为起始数据段来回应我。

3、主机A收到这个数据段后,再发送一个确认应答,确认已收到主机B 的数据段:我已收到回复,我现在要开始传输实际数据了。

C# TCP服务端思路

在这里插入图片描述

有此图可以看出服务器和客户端之间的编程思路
下面是两种思路的总结
首先是服务端

TCP C# Socket 编程思路
1.创建一个负责监听Socket,创建Socket并填基本属性值(Socket())
2.创建IP地址和端口号对象 (IPEndAdress())
3.让负责监听的Socket绑定IP地址和端口号(Bind())
4.创建监听队列(监听队列就是某一时间能连接进的客户端的最大数量使用Listen())
5.创建接受负责监听的Socket,来接受客户端的连接,创建跟客户端通信的Socket使用函数Accept();
6.收发数据:使用函数read()和write(),用函数send()和recv()也可以
7.关闭服务端

C# TCP服务端程序示例

软件使用的VS2019,框架使用了.Net Framework 4.5.2

首先创建Windows窗体程序
在这里插入图片描述

创建完成后
1.工具箱内有需要使用的所有控件
2.可以查看控件的属性
3.可以创建空间的事件
在这里插入图片描述
将界面设置成如图所示的样子(有问题留言)

在这里插入图片描述
按下F7或者右击-查看代码

之前有何大家讨论编程思路在这里我们可以按照这个思路编程
首先我们回到设计界面双击"连接"按钮添加一个点击事件
然后添加下面代码(此代码如果有疑问的地方可以私信我)

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.Sockets;
using System.Net;
using System.Threading;
 

namespace TCPIP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 窗口加载的时候取消程序对跨线程的检查
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            try
            {
                //当点击连接开始监听的时候,在服务端创建一个负责监听IP地址根端口号的Socket
                Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                //创建IP地址和端口号对象
                IPAddress ipAddress = IPAddress.Any;            
                IPEndPoint Port = new IPEndPoint(ipAddress, Convert.ToInt32(textBox2.Text));

                //绑定端口号
                socketWatch.Bind(Port);
                ShowMsg("连接成功");
                socketWatch.Listen(10);
                
                //等待客户连接,并创建一个负责通讯的socket并设置为后台线程
                Thread th = new Thread(Listen);
                th.IsBackground = true;
                th.Start(socketWatch);
            }catch { }
        }
  
        /// <summary>
        /// 消息显示
        /// </summary>
        /// <param name="str"></param>
        void ShowMsg(string str)
        {
            textBox3.AppendText(str + "\r\n");
        }

        /// <summary>
        /// 等待客户端连接,并创建与之通信用的Socket
        /// </summary>
        void Listen(Object o)
        {
            Socket socketWatch = o as Socket;
            //等待客户端连接,并创建与之通信用的Socket
            while (true)
            {
                Socket socketSend = socketWatch.Accept();
                ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功");
                //客户端接收成功后,服务器应该接收客户端发来的消息
                Thread th = new Thread(Rivice);
                th.IsBackground = true;
                th.Start(socketSend);

               
            }
            
        }
        Socket socketWatch;
        /// <summary>
        /// 服务器端不断地接收客户端发来的消息
        /// </summary>
        /// <param name="o"></param>
        void Rivice(object o)
        {
            Socket socketSend = o as Socket;
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[1024 * 1024 * 2];

                    int r = socketSend.Receive(buffer);
                    if (r == 0)
                    {
                        break;
                    }
                    string str = Encoding.UTF8.GetString(buffer, 0, r);
                    ShowMsg(socketSend.RemoteEndPoint + ":" + str);
                } catch { }
            }
        }
      }

以上便就是我们按照之前的思路所设计出来的
接下里我们可以测试一下
在这里插入图片描述

由于Windows10 telnet被阉割了,不方便之后的客户端调试,这里就网上冲浪随便下了一个TCP调试助手。
运行程序,将IP地址设置为自己电脑的IP地址 端口设置尽量设置后面一点 然后点击连接
在这里插入图片描述
打开TCP调试助手设置IP和端口
在这里插入图片描述
点击启用
在这里插入图片描述
在试一试服务端接受客户端的信息
在这里插入图片描述
OK!以上便是服务端的程序,如有疑问可以私信,此程序还有待优化,也欢迎大家的指点和建议。

C# TCP客户端思路

在这里插入图片描述
大家可以看到了,我有拿出了这张图片,因此可以看出此图的重要!此图的右边就是客户端思路
大家可以从上图清晰看的客户端相对于服务端少了,创建IP和端口对象,绑定端口和监听队列于管理请求,相比不用我说大家都可以想的八九不离十,下面是客户端的思路

TCP客户端思路
创建一个负责通信Socket,创建Socket并填基本属性值(Socket())
应用程序IP地址(端口号每一个应用程序系统都会分配一个端口号)
连接远程的服务端使用(Connect())

C# TCP客户端程序示例

我们在之前的服务器端代码下面添加下面这些代码

		/// <summary>
        /// 客户端发送消息给客户端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            
            string str = textBox4.Text.Trim();
            byte[] buffer = Encoding.UTF8.GetBytes(str);
            socketWatch.Send(buffer);
        }


        /// <summary>
        /// 清空
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            textBox3.Clear();
        }


        /// <summary>
        /// 客户端连接服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            try
            {
                //当点击连接开始监听的时候,在客户端创建一个负责监听IP地址根端口号的Socket
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPAddress ipAddress = IPAddress.Parse(textBox6.Text);
                //创建端口号对象
                IPEndPoint Port = new IPEndPoint(ipAddress, Convert.ToInt32(textBox5.Text));

                //连接端口号
                socketWatch.Connect(Port);
                Show("连接成功");
               
                
            }
            catch { }
        }
       /// <summary>
       /// 显示信息
       /// </summary>
       /// <param name="str"></param>
        void Show(string str)
        {
            textBox4.AppendText(str + "\r\n");
        }
    }

添加完成后我们进入TCP助手调试看一下
注意这里我们使用的下面的客户端界面

在这里插入图片描述
OK!我们在试一试发送一条信息
在这里插入图片描述
注意这里我的发送的连接成功文字变成了编程了乱码,在这里如果不想有乱码需要添加编码转换

以上便就是TCP服务和客户端的通讯,此程序还有可以完善的地方,各位有什么意见或者疑问的地方,欢迎指出。
[1]: https://www.cnblogs.com/IPrograming/archive/2012/10/18/CSharp_Socket_5.html


  1. 注脚的解释 ↩︎

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值