在网络学习中,前面简单说了一下fisjnet插件,但是作为网络部分只用插件显然是不足够的,本章开始记录底层的网络socket的使用,用简单的案例进行记录
本案例的流程为:头文件-类的创建-端点介绍-socket介绍-远程端点介绍-服务器和客户端的常规传输数据用法
案例:
cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SoketServer
{
internal class Program
{
private const int SrverPoint = 7777;
private static void main(string[] args)
{
//定义一个socket确定传输协议和类型
Socket ListenSoket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp
);
//定义一个端点,整合可以接受信息的地址以及端口号
IPEndPoint ServerIpEndPoint=new IPEndPoint(IPAddress.Any, SrverPoint);
//将socket绑定这个端点,用于监听要连接到这个端点的客户端
ListenSoket.Bind(ServerIpEndPoint);
//限制一次最多有10个连接
ListenSoket.Listen(10);
Console.WriteLine($"服务器启动成功,正在监听:{ListenSoket}");
Console.WriteLine("正在启动服务器");
//阻塞等待连接,如果有连接进来继续向下执行,给这个连接分配一个socket,该socket的参数为
//AddressFamily.InterNetwork,
//SocketType.Stream,
//ProtocolType.Tcp
//端点=监听端点ServerIpEndPoint
//远程端点=信息发送过来的服务器IP+临时分配端口号如52001
Socket ClientSocket =ListenSoket.Accept();
Console.WriteLine($"客户端连接成功:{ClientSocket.RemoteEndPoint}");
//创建一个byte数组用来存储发送过来的数据,网络传输的数据类型都是byte
byte[] receiveBuffer=new byte[1024];
//调用ClientSocket.Receive方法用于接受这条socket传输进来的信息,并存入receiveBuffer,这个方法的返回值会是一个int类型的值,代表这次消息的长度
int receiveLength =ClientSocket.Receive(receiveBuffer);
//检测本条消息的长度,当连接成功后每次消息传输都不会为空值,当消息长度等于0时代表连接断开
if( receiveLength == 0)
{
Console.WriteLine("客户端已关闭");
}
else
{
//进行字符转换为string让我们看得懂,传参类型为字符缓冲整体数组,从第0个开始到本次消息的数组长度,避免将数组中为用上的部分也去进行转换操作
string receivedMseeage = Encoding.UTF8.GetString(receiveBuffer, 0, receiveLength); ;
Console.WriteLine($"服务器收到客户端消息:{receivedMseeage}");
//准备回复客户端的消息内容为"服务器已经收到+receivedMseeage的内容"
string responseMseeage = $"服务器已经收到:{receivedMseeage}";
//消息准备好后在转换为byte类型以便传输
byte[] responseByte=Encoding.UTF8.GetBytes(responseMseeage);
//自己定义的方法,用于发送数据,确保发送指令上传,不确保一定传输成功
AllSend(ClientSocket, responseByte);
Console.WriteLine($"已成功回复客户端,共发送{responseByte.Length}字节");
}
//这里假设消息传输结束,一般不会只传输一条,将这条用于传输的socket双方断开
ClientSocket.Shutdown(SocketShutdown.Both);
//关闭并释放资源
ClientSocket.Close();
//关闭释放监听socket的缓资源
ListenSoket.Close();
}
/// <summary>
/// 用于传输信息,多次检测传输避免一次发送失败,传入用于消息传输的socket以及具体的消息data
/// </summary>
/// <param name="socket"></param>
/// <param name="data"></param>
/// <exception cref="InvalidOperationException"></exception>
private static void AllSend(Socket socket, byte[] data)
{
//用于计数当前传输到第多少字节
int dataCount = 0;
//循环检测,已经发送的字节是否满足总
while(dataCount<data.Length)
{
//调用原生Send发送信息,传入参数实际数据数组,本次传输开始的地方,本次还需发送多少字节,不使用额外Socket发送标志
int SendCount = socket.Send(data, dataCount, data.Length - dataCount, SocketFlags.None);
//检测如果本次传输的的信息长度为0,那么代表本次没有任何传输,代表传输失败抛出异常
if(SendCount<=0)
{
throw new InvalidOperationException("Socket没有成功发送数据。");
}
//将计数器加上本次的传输数量
dataCount += SendCount;
}
}
}
}
这就是一个简单的写在服务器上的程序,作用是监听客户端发送来的链接,然后分配socket进行通讯,接受到客户端的通讯后在向客户端发送通讯告知已接收到消息,断开双方链接,关闭socket,关闭服务器监听
这个案例很简单的讲解了一个简单的服务器处理客户端通讯的流程,下面做重点知识点详细拆解
1,using System.Net;
using System.Net.Sockets;
这两段头文件是网络连接必要的
2,private const int SrverPoint = 7777;
将7777这串数字记录下来,因为我们本节常用的就是7777端口号,以免后面每次打7777
3, Socket ListenSoket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
这里就是创建一个服务器用于通讯的Socket,服务器想要进行通讯会用哪种格式和协议,这里用来接受网络连接请求也就是用来监听想要主动向服务器发起的连接,连接方式采用IPV4,字节流,TCP协议,socket部分后面详细说明
4, IPEndPoint ServerIpEndPoint=new IPEndPoint(IPAddress.Any, SrverPoint);
封装一个端点,将网络IP以及端口号(上面创建的7777)封装到一起方便调用,一个计算机中会有很多的网络IP,有线网卡和无线网卡的网络IP都是不一样的,我们需要这个端点负责监听哪个IP,而IPAddress.Any代表的是任何IP,也就是说这个端点带表的是服务器电脑的所有网络IP监听连接请求
5,ListenSoket.Bind(ServerIpEndPoint);
将定义的Socket进行绑定端点,也就是说成为专门负责监听这个端点的socket,端点本身是不能处理客户端连接信息的,所以需要socket作为接口进行一系列操作
6,ListenSoket.Listen(10);
每次最多同时存在的连接数量限制,在监听接收到连接请求后,会给这条线路分配一个socket当作接口专门进行通讯,这个被自动分配的socket参数来自于监听的socket加上设置的监听端点加上远程用于发送信息的远程端点
7,Socket ClientSocket =ListenSoket.Accept();
由ListenSoket.Accept();阻塞函数负责监听连接,如果监听到了就将这个连接分配给自动socket进行操作
8,byte\[\] receiveBuffer=new byte1024;
创建一个数组用来放传输来的数组
9,int receiveLength =ClientSocket.Receive(receiveBuffer);
由自动分配的socket来接受消息,并将接收到的消息放进数组,这个方法会有一个返回值,返回本次传输的消息长度
10,if( receiveLength == 0) { Console.WriteLine("客户端已关闭"); }
连接成功后,每次接受都会有数据,如果本次传输没有数据代表客户端已经关闭
11, string receivedMseeage = Encoding.UTF8.GetString(receiveBuffer, 0, receiveLength);
字符转换为string
12,byte\[\] responseByte=Encoding.UTF8.GetBytes(responseMseeage);
字符转换为数据流
13,AllSend(ClientSocket, responseByte);
自己定义的方法,通过多次send确保数据发送的请求全部上传
14,ClientSocket.Shutdown(SocketShutdown.Both);
这里假设传输一条数据就结束连接,接下来是结束连接的流程,这段代码意思是断开双方的连接
15,ClientSocket.Close();
关闭socket并释放资源
16,ListenSoket.Close();
同样关闭监听的socket并释放资源
17, private static void AllSend(Socket socket, byte\[\] data)
传入用于通讯的socket以及通讯内容用于处理
18,int SendCount = socket.Send(data, dataCount, data.Length - dataCount, SocketFlags.None);
进行单次发送,一次肯定发送不完全,那就检测发送了多少字节,然后循环检测,如果没发送完那就在从上次发送到的地方开始继续发送,直到全都发送完
sockte到底是什么,干嘛的?
socket里面封装了网路信息传输的传输方式以及一些协议和规则,当两方需要进行网络传输的的时候,双方都需要一个socket才能将信息发送出去,可以理解为,枪想要发射子弹需要枪口,两个人想要打电话需要两台不同的电话,枪口和电话就是被封装好的socket,包括进行各种操作,只要是双方信息有关的,有需要用socket来进行
服务器的监听socket有什么特别的?
一般来说只有服务器需要监听socket,因为服务器其实作为中转站,中转的不只是聊天消息,更是游戏逻辑,移动,战斗,两个客户端都需要主动连接到服务器,所有数据传输都需要通过服务器,这也是避免一个客户端直接将数据传输到另一个客户端避开服务器的外挂检测,所以客户端不需要监听,只需要主动连接服务器就行