Socket通信(IP/TCP协议)

  1. 基本概念

    • IP/TCP:IP(Internet Protocol)即互联网协议,是一种用于在网络中寻址和路由数据包的协议。它为每个连接到互联网的设备分配一个唯一的 IP 地址,使得数据能够在不同的网络节点之间传输。TCP(Transmission Control Protocol)是传输控制协议,它建立在 IP 协议之上,提供可靠的、面向连接的通信服务。TCP 通过一系列机制,如三次握手建立连接、序列号和确认应答、滑动窗口进行流量控制、超时重传等,保证数据能够准确无误地从源端发送到目的端。
    • Socket 通信:Socket(套接字)是一种应用层与 TCP/IP 协议族通信的中间软件抽象层。它可以看作是在应用程序和网络协议栈之间的一个接口,通过 Socket,应用程序可以方便地使用 IP/TCP 等网络协议进行通信。简单来说,Socket 是对网络通信进行编程的一种接口机制。
  2. 相互关系

    • Socket 基于 IP/TCP 实现通信功能:Socket 提供了一套函数或方法,程序员可以使用这些接口来调用底层的 IP/TCP 协议功能。例如,在使用 Socket 进行网络编程时,当创建一个 TCP 套接字并调用相关函数进行连接操作时,实际上是在底层利用 TCP 协议的三次握手过程来建立连接。发送和接收数据的操作也是通过 TCP 的可靠传输机制来实现的,而 IP 协议则负责数据的路由和寻址,将数据从源 Socket 发送到目标 Socket 对应的 IP 地址。
    • IP/TCP 通过 Socket 提供给应用程序访问接口:IP/TCP 协议本身是比较复杂的网络协议,普通的应用程序很难直接使用这些协议进行通信。Socket 就像是一座桥梁,将复杂的 IP/TCP 协议封装成应用程序可以理解和使用的接口。例如,一个简单的网络聊天应用程序,开发人员可以使用 Socket 提供的接口(如创建套接字、绑定端口、监听连接、发送和接收消息等操作),而不需要深入了解 IP/TCP 协议的细节,就可以实现聊天程序的网络通信功能。
  3. 通信过程示例

    • 假设应用程序 A 要和应用程序 B 进行通信。首先,应用程序 A 通过 Socket API(应用程序编程接口)创建一个 Socket,指定使用 TCP 协议,并绑定一个本地端口。然后,应用程序 A 通过 Socket 发送一个连接请求,这个请求在底层通过 IP 协议进行寻址,找到应用程序 B 所在的设备 IP 地址,再通过 TCP 协议的三次握手过程与应用程序 B 建立连接。一旦连接建立成功,应用程序 A 和 B 就可以通过 Socket 接口发送和接收数据,这些数据在网络中通过 IP 进行路由,通过 TCP 进行可靠传输,确保数据能够正确地在两个应用程序之间传递。
  4. 应用场景优势

    • 广泛适用性:这种基于 Socket 和 IP/TCP 的通信方式被广泛应用于各种网络应用中。从简单的客户端 - 服务器应用(如网页浏览,浏览器作为客户端通过 Socket 和服务器建立 TCP 连接进行网页内容的获取)到复杂的分布式系统通信(如企业级的分布式数据库系统,不同节点之间通过 Socket 和 IP/TCP 进行数据同步和交互)都离不开这种通信方式。
    • 可靠性和灵活性:由于 TCP 提供了可靠的通信机制,结合 Socket 方便的编程接口,使得开发人员能够构建稳定、灵活的网络应用。例如,在远程文件传输应用中,利用 Socket 和 IP/TCP 可以确保文件数据完整、准确地在不同设备之间传输,并且可以根据实际情况(如网络带宽、文件大小等)灵活调整传输策略。

----------------------------调试工具(TCP Server服务器端、TCP Client客户端)

1.客户端连接服务器端(需要对应服务器端IP及端口号)

-------------------------手搓Socket服务器端及客户端

1.服务器端

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;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Server端
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //创建Socket 
        //套接字:进行网络链接字面变量
        public Socket socket;//用于通信
        public Socket ServerSocket;//服务器的监听  
        public Socket SocketAccept;//用来接收客户端的套接字
        //创建一个线程  用于监听
        Thread Thread1;
        //接收用户数据线程
        Thread Thread2;
        //开启服务器事件
        private void button1_Click(object sender, EventArgs e)
        {
            //关闭选中状态 防止再次生成链接对象
            button1.Enabled = false;
            button2.Enabled = true;
            //创建服务器链接对象
            //1.协议类型
            //2.链接套接字的双向数据流
            //3.设置TCP协议
            ServerSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

            //设置IP地址
            //IPAddress.Parse  将字符串转化为IP地址的实例
            IPAddress ip = IPAddress.Parse(textBox1.Text);
            //设置端口号
            int Port = Convert.ToInt32(textBox2.Text);
            //生成链接对象 
            IPEndPoint iPEndPoint = new IPEndPoint(ip,Port);

            //服务器调用.bind  绑定ip地址
            ServerSocket.Bind(iPEndPoint);
            //监听的数量  
            ServerSocket.Listen(20);
            //客户端与服务器端之间数据传输  一对多  
            //开启多线程
            //实例话线程  方法的名称  去做的事情
            Thread1 = new Thread(Fun);
            //将线程 设置为后台线程
            Thread1.IsBackground = true;
            //开启线程
            Thread1.Start(ServerSocket);


        }
        //Thread1方法
        // 线程 形参类型 使用object 保证你的数据不会丢失
        private void Fun(object Obj)
        {
            //接收Socket对象  
            SocketAccept = Obj as Socket;
            try
            {
                while (true)
                {
                    //添加线程阻塞   当未有客户端连接时不执行后续代码  知道有客户端链接 才去执行
                    socket = SocketAccept.Accept();

                    //当用户链接上之后  链接信息 显示在窗体上
                    //线程 直接显示在窗体上  线程错误  使用委托
                    //封装方法
                    //   SocketAccept.RemoteEndPoint 链接对象的IP地址
                    AddMsg($"{DateTime.Now.ToString("HH-mm-ss")},{socket.RemoteEndPoint}链接成功~~");


                    //客户端 发送数据 展示
                    Thread2 = new Thread(Display);
                    Thread2.Start(socket);

                }
            }
            catch (Exception)
            {

                throw;
            }
        }
        //接收客户端数据显示事件
        private void Display(Object Obj)
        {
            socket = Obj as Socket;
            //一直处于监听状态......
            while (true)
            {
                try
                {

                    //接收传数数据 byte -》编码  字符串
                    byte[] by = new byte[socket.ReceiveBufferSize];
                    //将字节添加至数组中
                    //Num是接收数量
                    int Num = socket.Receive(by);
                    //Num = 0 则表示本次未接收到客户端所传送消息 则不需要进行后续编码及显示操作 
                    if (Num == 0)
                    {
                        //暂停or终止线程
                        Thread2.Abort();
                        //搭配whlie + breck;终止...
                        break;
                    }
                    //编码操作
                    //string Str = Encoding.UTF8.GetString(by);
                    string Str = Encoding.Default.GetString(by);
                    AddMsg(Str);
                }
                catch (Exception)
                {

                    throw;
                }
            }


        }

        //委托 方法  避免线程错误
        private void AddMsg(string str) {
            //异步封装函数
            richTextBox1.BeginInvoke(new Action<string>(S => {
                richTextBox1.Text += S;
                richTextBox1.Text += "\n";
            }), str);
        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            //将添加内容起始点 放在了最后
            richTextBox1.SelectionStart = richTextBox1.Text.Length;
            //ScrollToCaret 将滚动条设置至光标or所添加内容区域
            richTextBox1.ScrollToCaret();
        }
        //关闭服务器事件
        private void button2_Click(object sender, EventArgs e)
        {
            button1.Enabled = true;
            //关闭所有进程
            if (socket != null) {
               socket.Shutdown(SocketShutdown.Both);
                socket.Close();   
                Thread2.Abort();
            }

            SocketAccept.Close();
            ServerSocket.Close();
            Thread1.Abort();
          
        }
        //发送消息
        private void button3_Click(object sender, EventArgs e)
        {
            //拿取richTextBox2中信息   字符串-》byte
            //richTextBox2.Text;
         byte[] by =    Encoding.Default.GetBytes(richTextBox2.Text);
            //发送数据
           
            socket.Send(by);
            //内容清空
            richTextBox2.Text = "";
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}

2. 客户端

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.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;

namespace Custom端
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //客户端链接
        public Socket CustomSocket;
        //创建一个线程  用于监听
        Thread Thread1;
        private void button1_Click(object sender, EventArgs e)
        {
            //关闭选中状态 防止再次生成链接对象
            button1.Enabled = false;
            button2.Enabled = true;
            //客户端 与服务器 建立链接...目标ip+端口   生成一个链接对象
            CustomSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //设置IP地址
            //IPAddress.Parse  将字符串转化为IP地址的实例
            IPAddress ip = IPAddress.Parse(textBox1.Text);
            //设置端口号
            int Port = Convert.ToInt32(textBox2.Text);
            //生成链接对象 
            IPEndPoint iPEndPoint = new IPEndPoint(ip, Port);
            //客户端与服务器建立链接
            CustomSocket.Connect(iPEndPoint);
            AddMsg($"{DateTime.Now.ToString("HH-mm-ss")}链接成功~~");
            //服务器调用.bind  绑定ip地址
            //   CustomSocket.Bind(iPEndPoint);
            //监听的数量  
            //  CustomSocket.Listen(20);
            //客户端与服务器端之间数据传输  一对多  
            //开启多线程
            //实例话线程  方法的名称  去做的事情
            Thread1 = new Thread(Fun);
            //将线程 设置为后台线程
            Thread1.IsBackground = true;
            //开启线程
            Thread1.Start(CustomSocket);

        }

       //接收消息
        private void Fun(object Obj)
        {
            //接收Socket对象  
            Socket SocketAccept = Obj as Socket;

            while (true)
            {
                byte[] by = new byte[SocketAccept.ReceiveBufferSize];
                int num = SocketAccept.Receive(by);
                if(num == 0)
                {
                    break;
                }
                string Str = Encoding.Default.GetString(by);
                AddMsg(Str);
            } 

        }
        //委托 方法  避免线程错误
        private void AddMsg(string str)
        {
            //异步封装函数
            richTextBox1.BeginInvoke(new Action<string>(S => {
                richTextBox1.Text += S;
                richTextBox1.Text += "\n";
            }), str);
        }
        //断开事件
        private void button2_Click(object sender, EventArgs e)
        {
            button1.Enabled = true;
            //关闭所有进程
            if (CustomSocket != null)
            {
                CustomSocket.Shutdown(SocketShutdown.Both);
                CustomSocket.Close();
                Thread1.Abort();
            }

       
        }

        private void button3_Click(object sender, EventArgs e)
        {
            byte[] by = Encoding.Default.GetBytes(richTextBox2.Text);
            //发送数据

            CustomSocket.Send(by);
            //内容清空
            richTextBox2.Text = "";
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值