C# Socket 使用教程

我在学习Socket时,总是感觉文章看不懂,视频又好长,所以留下这篇学习笔记,权当做同学间学习参考,与个人回顾吧.

简介

Socket(译做:管道/套接字)是一个便捷的类
用于封装通信时所涉及到复杂底层逻辑
也正因此我们就可以使用十分简便且直观的Socket类,并调用其中方法,就可轻松地实现数据通信/计算机间数据传输.

正文

所以,在Socket中,抽象出了服务端客户端的概念,并提供了其所需要的方法.

服务端

服务端的Socket实现流程是这样的:
1.创建socket对象

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//first is 寻址方式(此处是Ipv4)
//second is the socket's type(此处是流式传输)
//And the thrid is the 传输协议(或者说是信息传输方法)

2.绑定端口IP
我这里是从我写好的Winform窗体中获取的字符串.
其中txtIP是本机(服务端设备)IP地址;txtPort里填的是端口号,
我这里就先用的是31201,大家也可以在10000-6000之间随便填(好像是)

socket.Bind(new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text)));
//socket's Bind action need a IPEndPoint to bind the socket and the computer's ip and post
//(socket的Bing方法需要一个IPEndPoint来绑定socket和计算机的ip地址还有端口)
//so in the IPEndPoint we need a IPAddress and a int number(Post)
//所以在这个IPEndPoint中,我们需要一个IPAddress和一个数字(端口号)

3.开始侦听

socket.Listen(12233);//这个数字表示:同时排队的最大限制数量
//(这里是乱填的,一般改成100左右就可以了吧)
//是什么意思呢?:同时来了20000个链接请求,只能处理一个链接,
//队列里面放12233个等待链接的客户端,其他的返回错误消息。

4.开始接受客户端的链接

Socket proxSocket = serverSocket.Accept();//最好新开辟一个线程用来运行它
//this action is so especial(特殊) ,because the action will be 阻塞当前线程
//就是让它所在的线程停止工作,停在这个方法,
//直到侦测到客户端的请求才会返回一个代理Socket类型的变量
//(里面保存着客户端用来连接服务器端的socket的信息),然后继续往下执行
//So 这个方法每执行一次,往往就代表着,接收到了一个请求,并返回一个 代理Socket
//我们就可以读取这个代理socket的信息,并且调用它的Send方法,就可以实现信息的传递啦

5.接收数据

byte[] data = new byte[1024 * 1024];
proxSocket.Receive(data, 0, data.Length, SocketFlags.None);
string str = Encoding.UTF8.GetString(data, 0, len);//把拿到的二进制数字转换成字符串
//这个是拿到了代理的Socket对象,然后就Receive就行了
//挺抽象的是:这个也会像Accept一样阻塞住当前线程
//最后这个叫SocketFalgs枚举我也不知道是干啥的

并提供了向客户端传输数据的方法

byte[] data = Encoding.UTF8.GetBytes(txtMsg.Text);
proxSocket.Send(data, 0, data.Length, SocketFlags.None);//发送消息
//其中Encoding是一个类调用其中的静态UTF8方法会实例化一个Encoding的对象,
//然后调用其中的GetBytes方法,就会按照UTF8编码,把()中的内容转换为Bytes
//然后才能用Stream也就是流的传输模式来传输数据

客户端

客户端传输数据的逻辑和服务端十分类似,或者说,现在所提出的所谓从客户端与服务端两个方面去理解Socket,本身就是一个类的两种不同使用方法,所以,读到这里的同志,也请一定注意:Socket 本质上只是封装了通信功能的一个C#类,不要偏颇的仅仅以服务端和客户端的角度,去看待Socket,这是不全面的,服务端和客户端的功能,只是比较常见的需求,并应用了Socket技术,如此而已.
接下来是客户端的应用过程:
1.创建Socket对象

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

2.连接服务器端Socket

try//如果服务器的Listen队列已满,那么就会返回一个异常
{
  socket.Connect(new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text)));
//注意这里的txtIP.Text和txtPort.Text所填写的ip地址和端口都是服务端的
//逻辑上是:只要服务端的IP和端口固定了,那么客户端去找他就可以了,
//在连接之后,服务端就可以用,客户端连接后 自动生成的 代理Socket 与客户端进行消息的传递就可以了
}
 catch
{
  MessageBox.Show("当前服务器无法连接,请重试");
//如果愿意的话,可以把这段代码写成一个方法,然后在catch中调用自身,
//但是,要是一直连接不上的话,就怕一直递归下去会爆栈,所以还是有点危险的,
//有点影响程序鲁棒性,所以写个MessageBox得了
//暂停一秒,然后继续:
//Thread.Sleep(1000);
//调用自身方法体

3.接收服务器端消息

byte[] data = new byte[1024 * 1024];//一个可以存放1M数据的数组
int len = socket.Receive(data, 0, data.Length, SocketFlags.None);
//流式传输放到data里,len用来保存方法返回值,这个值是方法传递的字节数
string str = Encoding.UTF8.GetString(data, 0, len);
//服务和客户端双方一定要都用一套字符集,推荐UTF-8,
//如果是Defualt的话,他会按照系统默认字符集来传输/读取数据,
//字符集不同会出现乱码!

4.发送消息

byte[] data = Encoding.UTF8.GetBytes(txtMsg.Text);
socket.Send(data, 0, data.Length, SocketFlags.None);//发送消息

注意哦,我给出的代码例子,往往是可以直接在一个方法中使用的,但是,我不推荐这么做:
一是违反了面向对象的Single Responsibility Principle(单一责任原则);
二是,我给出的代码为了保证可读性(变量名可理解性)取名很直接.
尤其是在字符数组变量的data,存在变量名重复的问题,这时要么可以选择把他们放在不同的方法中,要么更改变量名,但是我更推荐把他们写在不同的方法中!

最后向大家说明一下,为什么客户端没有绑定IP地址和Post呢?
因为客户端在进行socket网络通信时,所携带的数据包就会包含自己的IP,而发送消息时所使用的端口则是由计算机自动分配的,
在第一次通信后,服务器就会保存相应的客户端ip和post到代理socket,以此来和客户端进行通信.

到了最最后,我想我应当给大家一些多线程的写法,以帮助大家写出更加丰满的程序,否则按照这个教程以上的知识,我们只能写出1对1的沟通程序,而这往往是具有一定局限性的.

Thread thread = new Thread(ParameterizedThrendStart((obj) = { }));//这里使用了有参委托
//ParameterizedThrendStart是官方提供的有参委托
//或者
//Thread thread = new Thread(ThrendStart(() = { }));
//ThrendStart是官方提供的无参委托
thread.IsBackground = true;
thread.Start(socket);

我想大家如果有一定C#基础的话可以看出,在这个线程的开辟中我们使用了,委托和Lambda表达式的相关知识,如果没学过可以去学,或者等我出学习日志,咱们一起学,咳咳,这些是后话
接下来更改了IsBackground的属性,将进程标志成了后台进程,然后开启了这个线程,线程将在执行完所有的ParmeterizedThrendStart委托中的方法后结束
C# IsBackground作用
这是前台进程和后台进程的区别
C#多线程系列(1):Thread
这是多线程系列课程


最最最后:
总结一下socket中常用的方法:
Bind
//绑定socket和ip地址与端口号
Listen
//表示的等待的链接上限,往往也与电脑配置有关,所以输一个超大的数,除了降低程序的安全性好像没啥大用,尽可能自己设置一个合理的上限吧
Accept
//等待连接,这个是服务端常用的一个方法,也是服务端和客户端通信最重要的一句话,创造连接,但是会阻塞线程,最好放在一个新的Thread里
Receive
//接收别的Thread给该程序(本机IP:程序占用端口)的数据,如果没有接收到,也会阻塞线程,最好也放在一个新的Thread里
Send
//Send用于发送某个东西,给这个socket,所以我们在客户端只需要服务端的IP地址,就是这个原因,我们得知道信息发送到哪去,而服务端,只需要调用Accept方法,等待客户端连接就可以了
Connect(new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text)));
//这个是只有客户端才用的,因为你得知道要发给谁才行,然后就是自动与这个地址的Accept联系就可以了
但是话又说回来,Accept,Receive,还有Connect往往都是很容易抛异常的,所以最好try一下
总结:
实质上,我们去观察Socket,往往就能发现,我在本机运行和调用Socket中的方法,实现通信,而我要一定要给予socket的的往往是我们要联系的目标的IP地址和端口,而我们本地,socket就可以与系统沟通,然后便宜行事了.
(类似于我知道对方的手机号,就可以通信,但是我自己的手机号,由电话卡帮我保管)
而在实现的过程中,我们往往需要抽象出信息的:发送方接收方,而我认为这也就是Tcp模式下socket的主要逻辑是,接收方绑定好端口等待连接,发送方调用Connect方法,寻找服务器,实际上就是接收方在等待,而发送方发送了沟通请求罢了
f5d37138-357b-46d3-ab69-85009e38c363

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容