C#のsocket通信
博主要做一个手机和电脑端(C#)通讯的程序,便览了网络上关乎socket的东西。但是接收文件的时候卡住了,怎么也接收不全。后来做了分片处理,如果分片,发送的时候就会有不同的socket(客户端开发不是我,故我不能控制人家怎么发),结果撞山了。
因为发送的时候for循环发,导致不是有重帧就是丢失,故进行了深入的研究。
1.Socket
Socket包括Ip地址和端口号两部分,程序通过Socket来通信,Socket相当于操作系统的一个组件。Socket作为进程之间通信机制,通常也称作”套接字”,用于描述IP地址和端口号,是一个通信链的句柄。说白了,就是两个程序通信用的。
更深刻理解引用一个同行的博文:http://blog.csdn.net/jiajia4336/article/details/8798421
生活案例对比:
Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。
注意:Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信。
2,端口进阶(深入)
端口号范围:0-65535,总共能表示65536个数。
按端口号可分为3大类
(1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。
(2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。
(3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。
通过IP地址确定了网络中的一台电脑后,该电脑上可能提供很多提供服务的应用,每一个应用都对应一个端口。
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件 ,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)
例如:http 使用80端口, ftp使用21端口 smtp使用25端口
3.Socket分类
Socket主要有两种类型:
- 流式Socket
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低
2,数据报式Socket
是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高
4. Socket一般应用模式(服务器端和客户端)
服务器端的Socket(至少需要两个)
01.一个负责接收客户端连接请求(但不负责与客户端通信)
02.每成功接收到客户端的连接便在服务器端产生一个对应的复杂通信的Socket
021.在接收到客户端连接时创建
022. 为每个连接成功的客户端请求在服务器端都创建一个对应的Socket(负责和客户端通信)
客户端的Socket
- 必须指定要连接的服务器地址和端口
- 通过创建一个Socket对象来初始化一个到服务器端的TCP连接
通过上图,我们可以看出,首先服务器会创建一个负责监听的socket,然后客户端通过socket连接到服务器指定端口,最后服务器端负责监听的socket,监听到客户端有连接过来了,就创建一个负责和客户端通信的socket。
下面我们来看下Socket更具体的通信过程:
Socket的通讯过程
服务器端:
01,申请一个socket
02,绑定到一个IP地址和一个端口上
03,开启侦听,等待接收连接
客户端:
01,申请一个socket
02,连接服务器(指明IP地址和端口号)
服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。
注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。
5.Socket的构造函数
Public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolTYpe)
AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接
SocketType:定义要打开的Socket的类型
Socket类使用ProtocolType枚举向Windows Sockets API通知所请求的协议
注意:
1,端口号必须在 1 和 65535之间,最好在1024以后。
2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。
如:
IPAddress addr = IPAddress.Parse("127.0.0.1");
IPEndPoint endp = new IPEndPoint(addr,,9000);
服务端先绑定:serverWelcomeSocket.Bind(endp)
客户端再连接:clientSocket.Connect(endp)
3,一个Socket一次只能连接一台主机
4,Socket关闭后无法再次使用
5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。
6.Socket常用类和方法
相关类:
IPAddress:包含了一个IP地址
IPEndPoint:包含了一对IP地址和端口号
方法:
Socket():创建一个Socket
Bind():绑定一个本地的IP和端口号(IPEndPoint)
Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量
Connect():初始化与另一个Socket的连接
Accept():接收连接并返回一个新的Socket
Send():输出数据到Socket
Receive():从Socket中读取数据
Close():关闭Socket,销毁连接
7、socket接收
博主就是因为网上的一些不良代码和思路被坑了不少时间,故此特意说明。
socket的接收缓冲区
我们都知道socket的接收方法使receive,receive是从socket缓冲区中读取,socket缓冲区是一个动态的东西,你读取一个,就相当于处理一个,就减少一个。
此缓冲区的意义:当前接收到的数据,意思是截止到你读取的时候里面的数据,这里面的数据是可以随着时间增加的。
我们可以理解为一个队列,发送方往队列中添加数据,receive取数据。
socket接收数据
windows的此缓冲区限制了大小为8k,故最多我们可以接受8k的数据,如果我们处理的过慢,又超过了发送方的超时时间,发送方就会显示超时。故同步处理就需要我们及时读取。否则,请异步处理,或者另起线程处理。
当然,如果我们双方约定了消息的大小,比如1k,那么我们接受的时候就可以每次读取1024个byte。
重点是,如果我们要读取一个文件,发送方使用一个socket的一次send,那么我们只能一次读取一个字节(约定为偶数的可以读取2个,约定4个或者8个的倍数的,可以读取4个或者8个),缓冲区的数据是按顺序到达的。
读取后,我们在重新拼装成消息,然后解析文件字段,还原为文件。
另:如果文件过大,切片后,不停的new socket发送是不可取的,可以尝试同一个socket发送(博主未验证)
上一段我接收的代码:
- private void ServerStart()
- {
- //创建IPEndPoint实例
- IPEndPoint ipep = new IPEndPoint(IPAddress.Any, Port);
- //创建socket套接字
- serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //将所创建的套接字与IPEndPoint绑定
- serverSocket.Bind(ipep);
- //设置socket为监听Listen模式
- serverSocket.Listen();
- while (true)
- {
- try
- {
- //在套接字上接收接入的连接
- Socket acceptSocket = serverSocket.Accept();
- if (acceptSocket != null)
- {
- Thread socketConnectedThread = new Thread(ReceiveData);
- socketConnectedThread.IsBackground = true;
- socketConnectedThread.Start(acceptSocket);
- //ThreadPool.SetMinThreads(100, 100);
- //ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), acceptSocket);
- Dispatcher.BeginInvoke((Action)(()=> {
- richTextBox.AppendText("\n有客户端接入...");
- }));
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show("listening Error: " + ex.Message);
- }
- }
- }
- private void ReceiveData(object obj)
- {
- Socket s = (Socket)obj;
- //根据收听到的客户端套接字向客户端发送信息
- IPEndPoint clientep = (IPEndPoint)s.RemoteEndPoint;
- try
- {
- List<byte> list = new List<byte>();
- byte[] buffer = new byte[];
- int readBytes = ;
- do
- {
- readBytes = s.Receive(buffer, , buffer.Length,SocketFlags.None);
- list.AddRange(buffer);
- }
- while (s.Available!=);
- byte[] buffers = list.ToArray();
- Dispatcher.BeginInvoke((Action)(() =>
- {
- richTextBox.AppendText("\nIP地址:" + clientep.Address + " 端口号:" + clientep.Port);
- }));
- byte[] messageBuffer = new byte[list.Count-];
- messageBuffer = buffers.Skip().Take(list.Count - ).ToArray();
- Message receive = MessageHelp.DeSerialize(messageBuffer);
- if (receive != null)
- {
- switch (receive.messageType)
- {
- case "link":
- ClientIp = receive.sourceIp;
- ClientPort = Convert.ToInt32(receive.sourcePort);
- //接到后发送ok
- byte[] sendData = MessageHelp.Serialize(new Message { messageType = "link", sourceIp = LocalIpAddress, sourcePort = Port.ToString(), content = "ok" });
- //s.Send(sendData, sendData.Length, SocketFlags.None);
- Socket toClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- toClient.Connect(new IPEndPoint(IPAddress.Parse(ClientIp), ClientPort));//与该ip地址进行连接
- toClient.Send(sendData, sendData.Length, SocketFlags.None);
- break;
- case "command":
- byte[] responseData = MessageHelp.Serialize(new Message { messageType = "command", sourceIp = LocalIpAddress, sourcePort = Port.ToString(), content = receive.content});
- Socket reClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- reClient.Connect(new IPEndPoint(IPAddress.Parse(ClientIp), ClientPort));//与该ip地址进行连接
- reClient.Send(responseData, responseData.Length, SocketFlags.None);
- Dispatcher.BeginInvoke((Action)(() =>
- {
- richTextBox.AppendText("\n" + receive.content);
- }));
- break;
- case "file":
- FileName = receive.fileName;
- byte[] csharpFileByte = new byte[receive.fileTotalLength];
- for (int i = ; i < receive.bytes.Length; i++)
- {
- csharpFileByte[i] = Convert.ToByte(receive.bytes[i] & 0xff);
- }
- System.IO.File.WriteAllBytes(FileName, csharpFileByte);
- MessageBox.Show("文件接收成功");
- //接到后发送ok
- byte[] responseFile = MessageHelp.Serialize(new Message { messageType = "file", sourceIp = LocalIpAddress, sourcePort = Port.ToString(), content = receive.content });
- //s.Send(sendData, sendData.Length, SocketFlags.None);
- Socket fClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- fClient.Connect(new IPEndPoint(IPAddress.Parse(ClientIp), ClientPort));//与该ip地址进行连接
- fClient.Send(responseFile, responseFile.Length, SocketFlags.None);
- break;
- }
- }
- }
- catch (Exception ex)
- {
- s.Close();
- }
- s.Close();
- s.Dispose();
- }
C#のsocket通信的更多相关文章
- 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- php简单实现socket通信
socket通信的原理在这里就不说了,它的用途还是比较广泛的,我们可以使用socket来做一个API接口出来,也可以使用socket来实现两个程序之间的通信,我们来研究一下在php里面如何实现sock ...
- Socket通信类
package com.imooc; import java.io.BufferedReader; import java.io.IOException; import java.io.InputSt ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍
一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...
- socket通信
socket通信 一:socket基于Tcp连接,数据传输有保证 二:socket连接的建立过程: 1:服务器监听 2:客户端发出请求 3:建立连接 4:通信 三:一个简单的例子:服务器端每隔一段时间 ...
- Android之Socket通信、List加载更多、Spinner下拉列表
Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务 ...
- .NET开源高性能Socket通信中间件Helios介绍及演示
一:Helios是什么 Helios是一套高性能的Socket通信中间件,使用C#编写.Helios的开发受到Netty的启发,使用非阻塞的事件驱动模型架构来实现高并发高吞吐量.Helios为我们大大 ...
- iOS开发之Socket通信实战--Request请求数据包编码模块
实际上在iOS很多应用开发中,大部分用的网络通信都是http/https协议,除非有特殊的需求会用到Socket网络协议进行网络数 据传输,这时候在iOS客户端就需要很好的第三方CocoaAsyncS ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-下载配置
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
随机推荐
- [android] 异步http框架与实现原理
介绍github上的异步http框架android-async-http loopj开发 获取AsyncHttpClient对象,通过new 调用AsyncHttpClient对象的get(url,r ...
- Java学习笔记之——继承
父类(基类):动物 子类:猫.狗.狼.老虎 如果子类继承于父类,则会自动拥有父类的所有非私有属性和方法,不会继承构造方法 父类和子类要满足一种关系:子类是父类的一种 Java中只支持单继承:一个子类只 ...
- 10个JavaScript常见BUG及修复方法
译者按: JavaScript语言设计太灵活,用起来不免要多加小心掉进坑里面. 原文: Top 10 bugs and their bug fixing 译者: Fundebug 为了保证可读性,本文 ...
- Django-Oscar小记:如何使用高版本Django开发网页的SEO模块
在使用Google搜索Django的SEO插件时,很多插件都没有更新到Python3.x,有的插件更新到了Python的高版本,但是不适用于Django的2.x. Django在升级到版本2.x的时候 ...
- 进入root提示Authentication failure错误
新安装Ubuntu 18.4,想进入root角色,提示“Authentication failure” 失败. 因为是新安装,并无root的密码,所以需要新增加: sudo passwd root,之 ...
- Python_json数据检索与定位之jsonPath类库
json数据检索与定位之jsonPath类库 by:授客 QQ:1033553122 实践环境 win7 64 Python 3.4.0 jsonpath_ng-1.4.3-py2.py3-non ...
- 接口自动化 [授客]基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0
基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0 by:授客 QQ:1033553122 博客:http://blog.sina.com.cn/ishou ...
- Android Studio手动打包
项目写完了,现在需要把应用上传到市场上面,那么怎么把项目打包成apk?(Android的可安装文件). 1. 创建签名文件 2. 填写好签名参数 3. 生成APK 注意:签名的密码和密匙的密码注意保管 ...
- Hibernate:查询
本文内容 OID查询 对象导航查询 HQL查询 QBC查询 SQL查询 首发日期:2018-07-31 hibernate的查询方式: hibernate有很多查询方式 OID查询 对象导航查询: H ...
- sh命令
sh或是执行脚本,或是切换到sh这个bash里,默认的shell是bash,你可以试试tcsh啊,csh啊,ksh,zsh什么的,看看别的shell是什么样子的.当然,linux中sh是链接到bash ...