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 ...
随机推荐
- SQL 語法
查詢 Sql = ("SELECT A1, A2, A5, A4 FROM Table1 ") 筆數 Sql = ("Select COUNT(*) From TW01. ...
- Spring核心——Bean的定义与控制
在Sring核心与设计模式的文章中,分别介绍了Ioc容器和Bean的依赖关系.如果阅读过前2文就会知道,Spring的整个运转机制就是围绕着IoC容器以及Bean展开的.IoC就是一个篮子,所有的Be ...
- virtualbox中 Kali Linux安装增强功能
1. 将VBoxLinuxAdditions.run文件copy出来 2. 赋予执行权限 chmod +x VBoxLinuxAdditions.run 3. 安装 ./VBoxLinuxAdditi ...
- 用函数式编程对JavaScript进行断舍离
译者按: 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! 原文: How I rediscovered my love for ...
- [小知识点] react 性能
场景: jsx 绑定方法 方法有3种 1: // 在html中,使用箭头函数,自动绑定this class SearchHistory extends React.Component { c ...
- 协程与Epoll的配合
想快速了解协程与网络调用的原来么,那么请赶紧关闭本页,因为下面都是在扯淡. 这几天是端午假期,第一天大算照着网上一大堆基于ucontext来写协程的文章自己也写一个简单的协程实现.于是第一天我就开始动 ...
- 洛谷P4588 [TJOI2018]数学计算(线段树)
题意 题目链接 Sol TJOI怎么全是板子题 对时间开个线段树,然后就随便做了.... #include<bits/stdc++.h> using namespace std; cons ...
- 朝花夕拾 - 应用了6年久经实际项目考验未变的代码 - singleton模式
最近整理自正式工作(从有上社保开始算起)8年来的知识.发现技术演变过程如下: 开发工具和.Net Famework: Visual Studio 2002 ->2003 -> 2005 - ...
- ngx-moment汉化
1.导入汉化文件 import '../../../node_modules/moment/locale/zh-cn.js' 2.使用汉化 <span>{{item.time|amLoca ...
- Android Service、IntentService,Service和组件间通信
Service组件 Service 和Activity 一样同为Android 的四大组件之一,并且他们都有各自的生命周期,要想掌握Service 的用法,那就要了解Service 的生命周期有哪些方 ...