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 ...
随机推荐
- Netty实战十三之使用UDP广播事件
1.UDP的基础知识 我们将会把重点放在一个无连接协议即用户数据报协议(UDP)上,它通常用在性能至关重要并且能够容忍一定的数据报丢失的情况下. 面向连接的传输(如TCP)管理了两个网络端点之间的连接 ...
- CSS-水平和垂直居中
div中水平和垂直居中 width:200px;height:200px; /*设置div的大小*/ border:1px solid green; /*边框*/ text-align: center ...
- SqL读取XML、解析XML、SqL将XML转换DataTable、SqL将XML转换表
DECLARE @ItemMessage XML )) SET @ItemMessage=N' <ReceivablesInfos> <ReceivablesList> < ...
- JDK和Tomcat安装
JDK安装: 1,选择安装位置,其余默认安装,安装两次,一个是JDK,一个是JRE,安装在两个文件夹中. 2,配置环境变量: 1,新建一个变量,变量名:JAVA_HOME,变量值:C:\Program ...
- CA 工作流程
散列函数 Hash 常见的有 MD5, SHA1, SHA256, 该类函数特点是函数单向不可逆,对输入非常敏感,输出长度固定,针对数据的任何修改都会改变散列函数的结果,用于防止信息篡改并验证数据的完 ...
- zTree 节点文字过多处理方法
zTree setting.view.addDiyDom 方法可以实现自定义控件,指定节点显示内容.因此需要自己实现addDiyDom方法. 如果树节点不显示checkbox ,处理方法为: func ...
- 章节一、1-Selenium简介
一.Selenium WebDriver介绍 1.跨平台,用web浏览器做自动化的工具. 2.可以在浏览器上运行的一个框架,用来进行界面的自动化. 3.支持多种计算机语言. 4.可以模拟真实的用户去操 ...
- awesomium_v1.6.6_sdk 百度云下载地址
awesomium的官网已经关闭很久了,所以找不到正规的下载地址. 而csdn上面的又收费.所以这里提供一个不收费的百度云的下载地址给大家. 不足就是不是1.7版本,所以对于某些有特殊用途的满足不了了 ...
- Unity3D 4.x编辑器操作技巧
unity wiki(en chs) unity官网 unity manual(chs 官方最新) 各个版本unity编辑器下载地址: https://unity3d.com/cn/get-un ...
- The concurrent snapshot for publication 'xxx' is not available because it has not been fully generated or the Log Reader Agent is not running to activate it
在两台测试服务器部署了复制(发布订阅)后,发现订阅的表一直没有同步过来.重新生成过snapshot ,也重新初始化过订阅,都不能同步数据,后面检查Distributor To Subscriber H ...