C# Socket的使用方法 及 简单实现

核心:

在服务器端和客户端的两个Socket实例,共同维持一个连接,而我们还需要一个服务端绑定了特定端口号的固定的serverSocket,用来监听远方clientSocket的申请,并为这个申请建立服务端对应的proxSocket

服务器维护:serverSocket

服务端实例 客户端实例 关系
proxSocket clientSocket 一一对应

一、要有服务端

--配置--

1、new Socket

Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

2、Bind

ServerSocket.Bind(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPost))); //服务器绑定本机IP和端口

3、Listen

ServerSocket.Listen(10); //最大连接数是10

4、Accept

Socket proxSocket = ServerSocket.Accept(); //监听Socket连接行为,并为监听到的链接创建Socket实例,会阻塞线程直到端口链接

--信息发送与传输--

5、Receive

proxSocket.Receive(data, 0, data.Length, SocketFlags.None); //data是要写入的byte数组,会阻塞线程直到侦听到slientSocket的Send并持续到IO结束

6、Send

proxSocket.Send(result, 0, result.Length, SocketFlags.None); //result是要上传的byte数组

二、还有客户端

--配置--

1、new Socet

ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

2、Connect

ClientSocket.Connect(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPort))); //尝试链接服务器的相应IP和端口,连接成功后,服务器端创建一个特定的proxSocket用来进行信息交换

--信息发送与传输--

3

ClientSocket.Receive(data, 0, data.Length, SocketFlags.None);

4

ClientSocket.Send(result, 0, result.Length, SocketFlags.None);

三、简单实现

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;namespace SockerDamo
{class SocketServer{List<Socket> ClientProxSocketList = new List<Socket>();//用于存放客户端链接Socket ServerSocket { get; set; }public void Start()//创建服务器Socket,开始侦听客户端,并开始循环接收消息{//1.创建socket对象Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);ServerSocket = serverSocket;//first is 寻址方式(此处是Ipv4)//second is the socket's type//And the thrid is the 传输协议System.Console.WriteLine("请输入IP地址:");String txtIP = Console.ReadLine();System.Console.WriteLine("请输入端口号:");String txtPost = Console.ReadLine();//2.绑定端口IPServerSocket.Bind(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPost)));//socket's Bind action need a IPEndPoint to bind the socket and the computer's ip and post//so in the IPEndPoint we need a IPAddress and a int number(Post)//3.开始侦听ServerSocket.Listen(20);//the number 表示 同时排队的最大限制数量//同时来了100个链接请求,只能处理一个链接,队列里面放20个等待链接的客户端,其他的返回错误消息。//4.开始接受客户端的链接//为了不阻塞主线程,我们应该把以下代码放在一个新的线程(池)中try{System.Console.WriteLine("开始监听链接...");Socket proxSocket = ServerSocket.Accept();//这个方法会阻塞当前线程,直到监听到链接AppendTextToTxtLog(string.Format("客户端{0}已链接", proxSocket.RemoteEndPoint.ToString()));byte[] data = new byte[1024 * 1024 * 256];//用来放数据的数组int len;while (true){System.Console.WriteLine("请选择模式:");System.Console.WriteLine("0.等待接收消息");System.Console.WriteLine("1.发送消息");string mo = Console.ReadLine();//获取客户端数据并返回读取的字节数,会阻塞当前线程,//当客户端突然掉线,往往会引发异常if (mo == "0"){try{len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);//往data数组里,从index=0开始,最长写入数据长度为data.Lengthif (data[0] == 0){StopConnect(proxSocket);}//正常退出逻辑else if (data[0] == 1){string str = Encoding.UTF8.GetString(data, 1, len - 1);//在data数组中从0开始,len个数据,转成strAppendTextToTxtLog(string.Format("接收到客户端:{0} 的信息是:{1}", proxSocket.RemoteEndPoint.ToString(), str));}}catch (Exception){Console.WriteLine("接收数据出错");StopConnect(proxSocket);}}else if (mo == "1"){SendMsg();}}}catch{AppendTextToTxtLog("出问题啦:您在接收客户端的请求的时候,发生了异常,夭寿啦```");}}private void StopConnect(Socket proxSocket)//停止链接{try{if (proxSocket.Connected){proxSocket.Shutdown(SocketShutdown.Both);proxSocket.Close(100);}}catch (Exception ex){System.Console.WriteLine("或许没有成功的停止连接" + ex.ToString());}}//发送消息private void SendMsg(){String txtMsg = Console.ReadLine();foreach (var proxSocket in ClientProxSocketList){if (proxSocket.Connected){byte[] data = Encoding.UTF8.GetBytes(txtMsg);//信息转二进制byte[] result = new byte[data.Length + 1];//信息的二进制放在1~data.Lengthresult[0] = 1;//第0个位置是标志位,将来我们可以用这个标志位,分辨文件类型,将来用来传文件Buffer.BlockCopy(data, 0, result, 1, data.Length);//把 data从0 转 result从1 长度data.Length proxSocket.Send(result, 0, result.Length, SocketFlags.None);//发送消息}}AppendTextToTxtLog(string.Format("{0}(本机) 的信息是:{1}", ServerSocket.LocalEndPoint.ToString(), txtMsg));}private void AppendTextToTxtLog(string txt){Console.WriteLine(txt);}}class SocketClient{Socket ClientSocket { get; set; }public void Start()//创建客户端Socket,并开始循环接收消息{#region 获取服务器端口内容System.Console.WriteLine("请输入服务器IP:");String txtIP = Console.ReadLine();System.Console.WriteLine("请输入端口号:");String txtPort = Console.ReadLine();#endregion//客户端链接服务器端//1.创建Socket对象ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//2.连接服务器端Sockettry//如果服务器的Listen队列已满,那么就会返回一个异常{ClientSocket.Connect(new IPEndPoint(IPAddress.Parse(txtIP), int.Parse(txtPort)));}catch{System.Console.WriteLine("当前服务器无法连接");//Thread.Sleep(1000);return;}//3.接收服务器端消息byte[] data = new byte[1024 * 1024 * 256];//传输数据放在这里,这里是256MB = 256 * 1024 KB = 256 * 1024 * 1024Byte int len;string str;string wenJianMing = "";while (true){System.Console.WriteLine("请选择模式:");System.Console.WriteLine("0.等待接收消息");System.Console.WriteLine("1.发送消息");string mo = Console.ReadLine();len = 0;str = null;if (mo == "0")try{len = ClientSocket.Receive(data, 0, data.Length, SocketFlags.None);//获取服务器端数据并返回读取的字节数,会阻塞当前线程,//当客户端突然掉线,往往会引发异常if (data[0] == 0)//模式0退出{AppendTextToTxtLog(string.Format("服务端:{0} 正常退出", ClientSocket.RemoteEndPoint.ToString()));StopConnect();}else if (data[0] == 1){//模式1收到了字符串str = Encoding.UTF8.GetString(data, 1, len - 1);AppendTextToTxtLog(string.Format("Socket信息:{0}", str));}//一次类推,总共有256种消息的传输模式}catch (Exception){AppendTextToTxtLog(string.Format("服务端:{0} 非正常退出",ClientSocket.RemoteEndPoint.ToString()));StopConnect();return;}else if(mo == "1"){SendMsg();}}// 也可以将第3步写入方法ReceiveData// Thread thread = new Thread(new ParameterizedThreadStart(ReceiveData));// thread.IsBackground = true;// thread.Start(); // 然后开启线程}private void AppendTextToTxtLog(string txt){Console.WriteLine(txt);}private void StopConnect(){try{if (ClientSocket.Connected){ClientSocket.Shutdown(SocketShutdown.Both);ClientSocket.Close(100);}}catch (Exception ex){System.Console.WriteLine("或许没有成功的停止连接" + ex.ToString());}}public void SendMsg(){if (ClientSocket.Connected){System.Console.WriteLine("请输入要发送信息的模式:");System.Console.WriteLine("0:结束");System.Console.WriteLine("1:字符串");String ms = Console.ReadLine();if (ms == "0") { }if (ms == "1"){System.Console.WriteLine("请输入要发送的消息:");String s = Console.ReadLine();byte[] data = Encoding.UTF8.GetBytes(s);byte[] result = new byte[data.Length + 1];//信息的二进制放在1~data.Lengthresult[0] = 1;//第0个位置是标志位,将来我们可以用这个标志位,分辨文件类型,将来用来传文件Buffer.BlockCopy(data, 0, result, 1, data.Length);//把 data从0 转 result从1 长度data.Length ClientSocket.Send(result, 0, result.Length, SocketFlags.None);//发送消息AppendTextToTxtLog(string.Format("本机的信息是:{0}", s));}}}}internal class Program{static void Main(string[] args){System.Console.WriteLine("0:服务器端");System.Console.WriteLine("1:客户端");string ms = Console.ReadLine();if (ms == "0"){SocketServer server = new SocketServer();server.Start();}else if (ms == "1"){SocketClient client = new SocketClient();client.Start();}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908061.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue中 this.$emit() 方法详解, 帮助子组件向父组件传递事件

this.$emit()是 Vue.js 中一个很有用的方法,可以帮助子组件向父组件传递事件前言 在Vue中,this.$emit()方法用于触发自定义事件。它是Vue实例的一个方法,可以在组件内部使用。 使用 this.$emit() 方法,可以向父组件发送自定义事件,并传递数据给父组件。父组件可以通过监听这…

Unity 运用新输入方法进行移动 (input System)

首先在包管理器中添加 input System重启后进入编辑项目中 找到玩家-配置 将Api兼容级别 改成 .NET Framework 活动输出处理改成 输入系统包(新)创建瓦片地图矩形 添加调色板 为瓦片地图添加Tilemap Collider 2D组件以及Composite Collider 2D(会自动添加Rigidbody 2d组件)组…

C#之Bitmap

SetPixel和GetPixel private void btnC_Click(object sender, RoutedEventArgs e) {OpenFileDialog dia = new OpenFileDialog();dia.Filter = "图像文件|*.png;*.bmp;*.jpg|所有文件|*.*";dia.Multiselect = false;if (dia.ShowDialog() == true){var fileName=dia.…

DVWA靶场 - Command Injection

Low 代码审计: 从源码中可以看出,代码只是执行了一个ping 命令,并没有对后面的参数做限制因此我们可以分别使用 ;、 |、||、&、&&进行注入;,命令行可以使用whoami、ipconfig/ifconfig、ls/dir 等Medium 代码审计: 对比代码发现,;和&& 被加入了黑名…

Linux基本使用-2

用户权限操作 1.su和exit命令 su [-] [用户名] 和 exit ==> 切换用户,不写默认为root;可用exit或者快捷键(ctrl+d)退至上一个用户 -表示切换用户后加载环境变量,建议带上 2.sudo和visudo命令 sudo 其他命令 ==> 为该命令临时授root权限,需为该用户==配置sudo认证 v…

leetcode每日一题:向字符串添加空格

题目 2109. 向字符串添加空格 给你一个下标从 0 开始的字符串 s ,以及一个下标从 0 开始的整数数组 spaces 。 数组 spaces 描述原字符串中需要添加空格的下标。每个空格都应该插入到给定索引处的字符值 之前 。例如,s = "EnjoyYourCoffee" 且 spaces = [5, 9] ,那…

jmeter 压测过程

测试策略 1、基准测试,获取无压力情况下,系统的平均响应时间; 2、采用持续并发的策略,获取系统的在不同压力下平均响应时间,TPS ; 3、在现有硬件资源下,获取到最高TPS; 4、在现有硬件资源下,持续较高TPS运行,验证系统的稳定性; 5、资源增加时,最大TPS是否可以线性增…

BaseMultiTableInnerInterceptor源码解读

本文首发在我的博客:https://blog.liuzijian.com/post/mybatis-plus-source-multi-table-inner-interceptor.html 一、概述 BaseMultiTableInnerInterceptor是MyBatis-Plus中的一个抽象类,位于mybatis-plus-jsqlparser-4.9模块中com.baomidou.mybatisplus.extension.plugins.…

test_your_nc 1(含前提简要)

前提简要: 虚拟机版本:Ubuntu24.04 pwn环境搭配如下(后面若有其他这个链接没有配置上的工具,都会在相应题目部分给出更新/分享/提示) Pwn环境搭建 都是基于个人理解,不一定完全正确!!! 题目:先启动靶机 方法一: 常规测试 直接在虚拟机nc与靶机进行连接 这道题连接后可能…

双向可控硅的基本原理阐述

双向可控硅的基本原理阐述正向--第1象限 (1)当T2、T1极间加正方向电压(即UT2〉UT1)时,如下图1-13(a)所显示。在这样的情况下,若G极无电压,则T2、T1极间不导通;若在G、T1极间加正方向电压(即UG〉UT1),T2、T1极间马上导通,电流由T2极流入,从T1极流出,这时移去G极…

DAPO: 面向开源大语言模型的解耦裁剪与动态采样策略优化系统

在人工智能技术快速迭代发展的背景下,大语言模型(LLMs)已成为自然语言处理与生成领域的核心技术。然而,将这些模型与人类偏好精确对齐并增强其复杂推理能力的挑战,促使研究者开发了一系列复杂的强化学习(RL)技术。DAPO(解耦裁剪和动态采样策略优化,Decoupled Clip and…