socket 概念讲解
计算机主机 都是独立的 硬件,而网络通信是 在多个主机进行通信的必要手段。
那么网络通信有什么内容,sockert又是什么。
首先 网络通信 一般来讲 分为5层 应用层-传输层-网络层-链路层-物理层
链路层-物理层 其实是 硬件方面的内容 比如 路由器网线这种
网络层 其实是对 网络协议的 规则制度 为了方便传输
真正需要 软件程序这边关注的 就是 传输层 和 应用层
传输层 就是 常用的 tcp udp 这些传输协议 提供信息传输
应用层 就是 常用的 http ftp 这种 已经准备好处理数据接收数据的协议
那么 socket 其实就是 传输层 的 底层原理
也就是说 实现传输层这个功能的 底层原理就是 socket技术 是socket 技术支持着TCP 和UDP 协议来进行传输
分类
既然传输层 有 TCP UDP 俩种
当使用TCP时,Socket通常被称为流式Socket(Stream Socket),它基于TCP协议,确保数据的可靠传输和有序性。
当使用UDP时,Socket则被称为数据报Socket(Datagram Socket),它基于UDP协议,提供了一种无连接的数据传输方式,不保证数据的可靠到达和顺序
TCP UDP 的区别
所以一般都是采用TCP 流的方式建立socket连接
角色
俩台主机进行通信连接 那么就会有 客户端 与 服务端 的角色
客户端负责请求消息 而服务端负责监听客户端的消息并进行连接
很经典的示意图片
具体使用相关函数
指令 | 描述 |
---|---|
connect()/BeginConnect | 客户端建立连接 |
bind() | 服务端绑定 |
listen() | 服务端监听 只负责监听 哪怕多个客户端进行连接请求 |
Accept/ BeginAccept | 服务端建立连接 创建一个新的socket(可以理解服务端connect的)对象 |
Send()/BeginSend | 客户端服务端进行发送消息操作 |
Receive/ BeginReceive | 客户端服务端进行接收消息操作 |
close() | 关闭操作 |
shutdown | 更细颗粒度的关闭功能 它允许分别或同时关闭读取、写入或两者 |
异步
在程序方面 建立通信也是需要 代码实现 也就是 线程去执行这些,那么线程在发展过程中 为了 实现 不阻塞等待过程的 手段发展出来 异步,那么 相应的sockert技术也有对应的异步函数进行调用
BeginAccept()服务端异步建立连接 BeginReceive()服务端异步接收消息
在使用异步的时候 主要参数 会有 一个是回调方法 一个是 状态参数
这个状态参数怎么理解呢 就是你有一些信息需要记录当下的然后传给回调方法的,比如当前一些连接的ip信息之类的 需要传到回调方法中去,所以微软这个状态参数 就是方便你自定义对象 将你所需要的 传给回调,然后回调方法中接收一下
就比如这个RecvStateObject 对象自定义的 里面有些值需要用到,那么就在回调之前附上内容,回调后方法中进行使用即可
异步接收信息还需要注意的一点就是:异步建立连接的情况回调后 是开辟新的socket 去进行后续消息的操作的,你可以理解为 有一个人专门负责连接 连接好之后就开辟一个新的socket 由它一直进行消息管理。
所以 这就是为什么在 AcceptCallback 连接回调后要 自定义对象 比如RecvStateObject 都会有一个属性叫workSocket,就是把连接后新建立的socket 作为后续消息交互的工作者这个状态信息保留住,然后在BeginReceive以及回调中传自定义对象就是为了能一直使用它
通过测试可以看出来 下方我会给出测试代码片段
以下测试用例 是以 net 8.0 控制台项目创建
客户端
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.IO;
namespace Client
{
class Program
{
static void Main(string[] args)
{
Client.StartClient();
Console.Read();
}
}
// 异步建立通信后 后续交互信息所使用的自定义状态对象
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class Client
{
// 端口号
private const int port = 8848;
// ManualResetEvent 设置线程同步
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
public static void StartClient()
{
try
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// 异步建立连接
Console.WriteLine("客户端建立连接sockertID:" + client.Handle); //Handle 句柄你可以理解为ID
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client