前言
以前也整理过吧,写了几篇之后,感觉没啥整理的必要了然后就放弃了,最近又想整理一下。
正文
这篇对应的是:https://www.cnblogs.com/aoximin/p/12235333.html,可以说是这篇的重写吧。
首先介绍一下什么是socket的,如果搞学术的不知道,他们可能要求的比较严,但是对于码农来说,socket可以说是向操作系统申请网络资源。
这个资源可以让我们发送数据和接收数据,这样就可以了。就像我们上面那篇文章写的,操作系统就是服务端,我们写的都是客户端,我们做的就是和服务端打交道。
如果真的想了解这个socket,那么应该去了解操作系统,如果是了解网络,初学的话,那大可不必。
就跟前后端一样,后端告诉你一个token,然后前端总纠结这个token是啥,我觉得大可不必,你传给我服务端我就给你过呗。
有时候我们要放大我们的思维,有时候我们要缩小自己的思维。 如果从客户端的角度去考虑socket,就跟前端去考虑token 是一样的,又痛苦又无趣。当你花点时间去了解后端,这个问题自然就解了。天生万物,道法自然,一切都是机缘,不要强求。
现在了解了,socket 就是资源。
有了操作系统给我们的socket 的资源后,我们就可以做一些其他事情了。
比如我们告诉操作系统,我们要占用127.0.0.1 的 8888 端口。
那么我们可以使用bind 来告诉操作系统。以前我有个误区,就是一只理解bind为绑定的意思,后面我理解的是应该是申请的意思。
要申请这个127.0.0.1 8888这个资源。所以如果有一个程序申请了这个资源,其他程序就不能申请了。
通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
但是我们知道,这个返回的socket 是个描述符,假如我们的这个描述符给其他程序使用,那么是否能共享这个资源呢?
如果这个成立,那么一切都回到了资源这个话题,而不能再说什么占用的情况,什么程序之间不能公用一个网络的情况。
这个后面提及,不然一直往外推,就太大了。
现在回到了socket这个话题了。bind 申请了这个套接字占用了某个网络资源了。
那么为何我们要进行listen呢? bind 是资源占用,现在操作系统记录了这个网络资源属于某个socket了,其他socket就不能占用了。
但是有个问题,就是占用相当于操作系统内部的操作。操作系统可没有说要处理收到的消息啊。
操作系统处理消息相当于流水线,消息过来了,但是我们的指挥部还没要处理到127.0.0.1 8888地址的消息啊。
那么listen 就是告诉流水线,处理一下127.0.0.1 8888的消息,有到这个的地址的包裹存一下。
那么现在流水线上的资源会被存起来了,但是这个是存到了操作系统了,还没到我们的程序。
这个时候客户端程序已经可以发送连接和消息到我们作为服务器申请了127.0.0.1 8888的这台机器了。
前面说了包裹还在我们操作系统那里,那么就得问一下(accept),有没有人发包裹给我。
然后操作系统如果有的话,就会告诉隔壁家的大爷发了点东西给你。
这个时候你就会拿到客户端会话,然后给操作系统说接受一下(receive)包裹吧。
这个时候我们思考一下问题,那就是tcp是双向通信的,这个时候我要收大爷包裹的时候,突然大爷掉线了,tcp断了。
请问这个时候操作系统还会给我包裹吗?
远程主机强迫关闭了一个现有的连接。
这时候你就会收到上面这个,这个时候操作系统就不给你缓存的包裹了,至于操作系统啥时候清空缓存这是操作系统干的事情。
这个时候再思考另外一个问题,如果是大爷发了包裹给我,然后又断开了。这个时候我们才开始进行accept,操作系统还会告诉我们大爷给过包裹吗?
是会的,来电显示还是会给的。
这大概就是基本的tcp 通信了。
自己写的测试代码 .net 6:
service:
// See https://aka.ms/new-console-template for more information
using System.Net;
using System.Net.Sockets;
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipAddress = IPAddress.Parse("127.0.0.1");
EndPoint endPoint = new IPEndPoint(ipAddress, 8888);
socket.Bind(endPoint);
socket.Listen();
Console.ReadLine();
var clientSocket = socket.Accept();
var receiveMessage = new Byte[1000];
clientSocket.Receive(receiveMessage);
Console.WriteLine(System.Text.Encoding.UTF8.GetString(receiveMessage));
Console.ReadLine();
client:
// See https://aka.ms/new-console-template for more information
using System.Net;
using System.Net.Sockets;
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipAddress = IPAddress.Parse("127.0.0.1");
EndPoint endPoint = new IPEndPoint(ipAddress, 8888);
socket.Connect(endPoint);
socket.Send(System.Text.Encoding.UTF8.GetBytes("hello service"));
Console.ReadLine();
结
以上只是个人理解,可能存在错误,望请指出。