相关文章推荐
冲动的香槟  ·  南山大事紀 - 南山中學·  3 月前    · 
开朗的打火机  ·  ReferenceError: ...·  4 月前    · 
谦和的移动电源  ·  docker-compose ...·  5 月前    · 

一、套接字

1.1 简介

  • 套接字是通信的基石,是支持TCP/IP协议的路通信的基本操作单元。可以将套接字看作不同主机间的进程进行双间通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序),各种进程使用这个相同的域互相之间用Internet协议簇来进行通信 。
  • Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的API(应用程序编程接口),也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 Socket中,该 Socket通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 Socket中,使对方能够接收到这段信息。 Socket是由IP地址和端口结合的,提供向应用层进程传送数据包的机制 。

1.2 主要特点

  • 面向连接服务的主要特点如下:

(1)数据传输过程必须经过建立连接、维护连接和释放连接3个阶段 ;
(2)在传输过程中,各分组不需要携带目的主机的地址 ;
(3)可靠性好,但由于协议复杂,通信效率不高 。

  • 面向无连接服务的主要特点如下:

(1)不需要连接的各个阶段;
(2)每个分组都携带完整的目的主机地址,在系统中独立传送;
(3)由于没有顺序控制,所以接收方的分组可能出现乱序、重复和丢失现象;
(4)通信效率高,但可靠性不能确保。

二、在命令行输出信息,用UDP套接字给其他电脑发送信息。

工具: Visual Studio 2019

  • 进入Visual Studio,新建项目,看看有没有Windows窗体应用和控制台程序这两选项
    在这里插入图片描述
  • 如果没有打开Visual Studio的安装程序,点击修改,选上通用Windows平台开发 在这里插入图片描述
  • 下好之后选择控制台程序新建项目,选择控制台应用程序,记得建立两个,一个为客户端,一个为服务器端 在这里插入图片描述
  • 服务器端代码,等待客户端的连接以及发送的信息
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace UDP
    class Program
        static void Main(string[] args)
            int recv;
            byte[] data = new byte[1024];
            //得到本机IP,设置UDP端口号         
            IPEndPoint ip = new IPEndPoint(IPAddress.Any, 8001);
            Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //绑定网络地址并监听
            newsock.Bind(ip);
            Console.WriteLine("This is a Server, host name is {0}", Dns.GetHostName());
            //等待客户机连接
            Console.WriteLine("Waiting for a client");
            //得到客户机IP
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)(sender);
            recv = newsock.ReceiveFrom(data, ref Remote);
            Console.WriteLine("Message received from {0}: ", Remote.ToString());
            Console.WriteLine(Encoding.UTF8.GetString(data, 0, recv));
            //客户机连接成功后,发送信息
            string welcome = "你好 ! ";
            //字符串与字节数组相互转换
            data = Encoding.UTF8.GetBytes(welcome);
            //发送信息
            newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
            while (true)
                data = new byte[1024];
                //接收信息
                recv = newsock.ReceiveFrom(data, ref Remote);
                Console.WriteLine(Encoding.UTF8.GetString(data, 0, recv));
                //newsock.SendTo(data, recv, SocketFlags.None, Remote);
  • 客户端代码,连接了服务器端之后会发送信息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace UDPClient
    class Program
        static void Main(string[] args)
            byte[] data = new byte[1024];
            string input, stringData;
            //构建TCP 服务器
            Console.WriteLine("This is a Client, host name is {0}", Dns.GetHostName());
            //设置服务IP(这个IP地址是服务器的IP),设置TCP端口号
            IPEndPoint ip = new IPEndPoint(IPAddress.Parse("192.168.43.233"), 8001);
            //定义网络类型,数据连接类型和网络协议UDP
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            string welcome = "你好! ";
            data = Encoding.UTF8.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ip);
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)sender;
            data = new byte[1024];




    

            //对于不存在的IP地址,加入此行代码后,可以在指定时间内解除阻塞模式限制
            int recv = server.ReceiveFrom(data, ref Remote);
            Console.WriteLine("Message received from {0}: ", Remote.ToString());
            Console.WriteLine(Encoding.UTF8.GetString(data, 0, recv));
            int i = 0;
            while (true)
                string s = "hello cqjtu!重交物联2019级" + i;
                Console.WriteLine(s);
                server.SendTo(Encoding.UTF8.GetBytes(s), Remote);
                if (i == 50)
                    break;
                i++;
            Console.WriteLine("Stopping Client.");
            server.Close();
  • 需要先打开服务器端,再打开客户端,运行的结果如下图
    在这里插入图片描述

三、From窗口按下按钮发送信息

  • 新建项目,选择Windows床体应用,两个,也是客户端和服务器端在这里插入图片描述
  • 客户端界面
    在这里插入图片描述
  • 客户端代码,记得代码是在From1.cs里的,如果是复制,记得引用函数
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 muti_thread_client
    public partial class Form1 : Form
        public Form1()
            InitializeComponent();
        Socket socketSend;
        private void button1_Click(object sender, EventArgs e)
            socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint point = new IPEndPoint(IPAddress.Parse("192.168.43.233"), 8001);
            socketSend.Connect(point);
            showMsg("连接成功!");
            Thread th = new Thread(Receive);
            th.IsBackground = true;
            th.Start();
        //客户端接收服务器发送的消息
        void Receive()
                while (true)
                    byte[] buffer = new byte[1024 * 1024 * 2];
                    int r = socketSend.Receive(buffer);
                    if (r == 0)
                        break;
                    string str = Encoding.UTF8.GetString(buffer, 0, r);
                    Invoke(new Action(() => {//在线程里修改界面
                        showMsg(socketSend.RemoteEndPoint + ":" + str);
                    }));
            catch
        void showMsg(string s)
            textBox1.AppendText(s + "\r\n");
        //客户端向服务器发送消息
        private void button2_Click(object sender, EventArgs e)
            string str = textBox2.Text;
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
            socketSend.Send(buffer);  
  • 服务器端界面在这里插入图片描述
  • 服务器端代码
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 muti_thread_server
    public partial class Form1 : Form
        string str="没有改变";
        public Form1()
            InitializeComponent();
        private void button1_Click(object sender, EventArgs e)
                //点击开始侦听的时候,服务器创建一个负责监听IP地址跟端口号的Socket
                Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Any;
                //创建端口对象
                IPEndPoint point = new IPEndPoint(ip, 8001);
                socketwatch.Bind(point);
                showMsg("监听成功!");
                socketwatch.Listen(10);
                //创建一个线程
                Thread th = new Thread(listen);
                th.IsBackground = true;
                th.Start(socketwatch);
            catch
                showMsg("监听失败");
        Socket socketSend;
        //等待客户端的连接
        void listen(Object o)
                Socket socketwatch = o as Socket;
                int i = 0;
                while (true)
                    //等待客户端的连接
                    socketSend = socketwatch.Accept();
                    str = socketSend.RemoteEndPoint.ToString() + ":" + "连接成功!";
                    Invoke(new Action(() => {//在线程里修改界面
                        showMsg(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功!");
                    }));
                    Thread th = new Thread(Receive);
                    th.IsBackground = true;
                    th.Start(socketSend);
            catch
        //接收客户端发送的信息
        void Receive(Object o)
                Socket socketSend = o as Socket;
                while (true)
                    byte[] buffer = new byte[1024 * 1024 * 2];
                    int r = socketSend.Receive(buffer);
                    if (r == 0)
                        break;
                    string str = Encoding.UTF8.GetString(buffer, 0, r);
                    Invoke(new Action(() => {//在线程里修改界面
                        showMsg(socketSend.RemoteEndPoint + ":" + str);
                    }));
            catch
        void showMsg(string str)
            textBox1.AppendText(str + "\r\n");
        //服务器给客户端发送消息
        private void button2_Click_1(object sender, EventArgs e)
            string str = textBox2.Text;
            Console.WriteLine(str);
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
            socketSend.Send(buffer);

四、单线程端口扫描器

端口扫描器是利用TCP去连接端口,如果能连接上就代表端口是开放的,如果连接不上就代表端口是没有开发的

  • 也是窗体应用,就直接放界面图了在这里插入图片描述
  • 主要代码,也是发送信息加入代码的那个文件
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Port_scan
    public partial class Form1 : Form
        public Form1()
            InitializeComponent();
        //自定义变量
        private int port;//记录当前扫描的端口号
        private string Address;//记录扫描的系统地址
        private bool[] done = new bool[65536];//记录端口的开放状态
        private int




    
 start;//记录扫描的起始端口
        private int end;//记录扫描的结束端口
        private bool OK;
        private void button1_Click(object sender, EventArgs e)
            label4.Text = textBox2.Text;
            label6.Text = textBox3.Text;
            progressBar1.Minimum = Int32.Parse(textBox2.Text);
            progressBar1.Maximum = Int32.Parse(textBox3.Text);
            listBox1.Items.Clear();
            listBox1.Items.Add("端口扫描器v1.0.");
            listBox1.Items.Add("");
            PortScan();
        private void PortScan()
            start = Int32.Parse(textBox2.Text);
            end = Int32.Parse(textBox3.Text);
            //判断输入端口是否合法
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
                listBox1.Items.Add("开始扫描:这个过程可能需要等待几分钟!");
                Address = textBox1.Text;
                for (int i = start; i <= end; i++)
                    port = i;
                    Scan();
                    progressBar1.Value = i;
                    label5.Text = i.ToString();
                while (!OK)
                    OK = true;
                    for (int i = start; i <= end; i++)
                        if (!done[i])
                            OK = false;
                            break;
                listBox1.Items.Add("扫描结束!");
                MessageBox.Show("输入错误,端口范围为[0,65536]");
        //连接端口
        private void Scan()
            int portnow = port;
            done[portnow] = true;
            TcpClient objTCP = null;
                objTCP = new TcpClient(Address, portnow);
                listBox1.Items.Add("端口" + portnow.ToString() + "开放");
            catch

五、多线程端口扫描器

  • 原理和单线程扫描其实是一样的,不过把扫描放到子线程里面去了,页面也是一样的,下面是代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace muti_thread_port_scan
    public partial class Form1 : Form
        public Form1()
            InitializeComponent();
        //自定义变量
        private int port;//记录当前扫描的端口号
        private string Address;//记录扫描的系统地址
        private bool[] done = new bool[65536];//记录端口是否已经扫描
        private int start;//记录扫描的起始端口
        private int end;//记录扫描的结束端口
        private bool OK;
        private Thread scanThread;  
        private void Form1_Load(object sender, EventArgs e)
        private void label4_TextChanged(object sender, EventArgs e)
            label4.Text = textBox2.Text;//设定进度条的起始端口
        private void label6_TextChanged(object sender, EventArgs e)
            label6.Text = textBox3.Text;//设置进度条的终止端口
        private void button1_Click(object sender, EventArgs e)
            label4_TextChanged(sender, e);
            label6_TextChanged(sender, e);
            //创建线程
            Thread procss = new Thread(new ThreadStart(PortScan));
            procss.Start();
            //设定进度条的范围
            progressBar1.Minimum = Int32.Parse(textBox2.Text);
            progressBar1.Maximum = Int32.Parse(textBox3.Text);
            //显示框的初始化
            listBox1.Items.Clear();
            listBox1.Items.Add("端口扫描器 v1.0");
            listBox1.Items.Add(" ");
        private void PortScan()
            start = Int32.Parse(textBox2.Text);
            end = Int32.Parse(textBox3.Text);
            //检查端口的合法性
            if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
                Invoke(new Action(() => {//在线程里修改界面
                    listBox1.Items.Add("开始扫描:这个过程可能需要等待几分钟!");
                }));
                Address = textBox1.Text;
                for (int i = start; i <= end; i++)
                    port = i;
                    //对该端口进行扫描的线程
                    scanThread = new Thread(Scan);
                    scanThread.Start();
                    //使线程睡眠
                    System.Threading.Thread.Sleep(100);
                    Invoke(new Action(() => {//在线程里修改界面
                        progressBar1.Value = i;
                        label5.Text = i.ToString();
                    }));   
                //未完成时情况
                while (!OK)
                    OK = true;
                    for (int i = start; i <= end; i++)
                        if (!done[i])
                            OK = false;
                            break;
                Invoke(new Action(() => {//在线程里修改界面
                    listBox1.Items.Add("扫描结束!");
                }));
                System.Threading.Thread.Sleep(1000);
                Invoke(new Action(() => {//在线程里修改界面
                    MessageBox.Show("输入错误,端口范围为[0,65536]");
                }));
        private void Scan()
            int portnow = port;
            //创建线程变量
            Thread Threadnow = scanThread;
            done[portnow] = true;
            //创建TcpClient对象,TcpClient用于TCP网络服务提供客户端连接
            TcpClient objTCP = null;
            //扫描端口,成功就写入信息
                objTCP = new TcpClient(Address, portnow);
                Invoke(new Action(() => {//在线程里修改界面
                    listBox1.Items.Add("端口" + portnow.ToString() + "开放!");
                }));
                objTCP.Close();
            catch
  • 效果
    在这里插入图片描述
  • 多线程扫描时的抓包结果,在info栏可以看到端口,看到端口的扫描顺序和我们代码里写的是一致的,而后面顺序比较混杂,是因为端口连不上也会有一系列命令,所以才造成这种局面
    在这里插入图片描述
  • 对比单线程扫描和多线程扫描,多线程的可视化界面明显比单线程更加流畅,这大抵是因为单线程既要运行程序,又要改变界面才导致的卡顿,而多线程没有这个毛病,效率也比单线程高。
  • 套接字编程蛮方便的,只需要配置一下ip地址、端口以及连接方式就行了,并没有想象中的那么复杂。

C#利用套接字实现数据发送
利用单线程和多线程实现端口扫描器

少年一、套接字1.1 简介1.2 主要特点二、在命令行输出信息,用UDP套接字给其他电脑发送信息。三、From窗口按下按钮发送信息四、单线程端口扫描器五、多线程端口扫描器六、总结七、参考一、套接字1.1 简介套接字是通信的基石,是支持TCP/IP协议的路通信的基本操作单元。可以将套接字看作不同主机间的进程进行双间通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可
转自:http://topic.csdn.net/u/20100514/22/d678924a-9b1c-4c4f-ace5-e71050d8fed1.html?r=77549674 不知道大家有没有遇见,UdpClient在监听的时候,不管同步还是异步的,调用Close()方法或者调用线程的Abort()方法,会抛出一个异常或者出现一个正在终止线程的小窗体,我理解是UdpClient正在等待接
UDP是面向无连接的,尽最大努力交付的不可靠通信协议。        相比TCP,少了握手建立连接,维护连接,连接释放等一系列过程,因此具有很小的资源消耗和处理速度快的点。        可实现一对一,一对多,多对一,多地多的UDP Client通信。        不同于TCP,UDP应用上已经无严格意义上的真正的服务器和客户端之分了,端点之间都是平等的关系。
IPEndPoint(IPAddress.Any, 0) If creates an IPEndpoint using any available IP address on the local computer, and any available port number. IPAddress.Any代表本机上的所有IP地址,MSDN上说是“一个 IP 地址,指示服务器应侦听所有网络接口
目录套接字简介UDP套接字给其它电脑发送消息Form窗口程序发送端口扫描器.1 单线程.2 多线程wireshark抓包总结参考 套接字简介 所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口。 UDP套接字给其它电脑发送消息 新建两个控制台应用程序: 一个为服务
UDP 是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。它是IETF RFC 768是UDP的正式规范。 UDP报头   UDP报头由4个域组成,其中每个域各占用2个字节,具...
要连接SQL Server和Visual Studio(VS)使用C#,您需要使用.NET Framework中的ADO.NET库。以下是连接步骤: 1. 在Visual Studio中创建一个新的C#项目。 2. 在项目中添加一个新的数据源。右键单击项目,选择“添加”>“新建项”>“数据”>“数据集”。 3. 在“添加新数据源”对话框中,选择“数据库”>“下一步”。 4. 在“选择数据源”对话框中,选择“Microsoft SQL Server”>“下一步”。 5. 在“连接到数据库”对话框中,输入SQL Server的服务器名称和身份验证信息。单击“测试连接”以确保连接正常。单击“下一步”。 6. 在“选择数据库对象”对话框中,选择要使用的数据库和表。单击“完成”。 7. 在项目中添加一个新的Windows窗体。将DataGridView控件拖放到窗体上。 8. 右键单击DataGridView控件,选择“数据绑定”>“数据源配置”。 9. 在“数据源配置向导”中,选择“对象”>“数据集”>“下一步”。 10. 在“选择数据源”对话框中,选择您在步骤5中创建的数据源。单击“下一步”。 11. 在“选择数据表”对话框中,选择您在步骤6中选择的表。单击“下一步”。 12. 在“选择数据列”对话框中,选择要在DataGridView中显示的列。单击“完成”。 13. 在代码中,使用SqlConnection和SqlCommand类来执行SQL查询并将结果绑定到DataGridView控件。 这是一个基本的连接SQL Server和Visual Studio的C#示例。您可以根据您的需求进行修改和扩展。