【转】C# Socket编程(5)使用TCP Socket
【转自:https://www.cnblogs.com/IPrograming/archive/2012/10/18/CSharp_Socket_5.html】
TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer),TCP协议能够检测和恢复IP层提供的主机到主机的信道中可能发生的报文丢失、重复以及其他错误。由于TCP协议是一种面向连接协议:在使用它进行通信之前,两个应用程序之间首先要建立一个TCP连接。TCP能够在网络中提供双工和可靠的的服务。
1.TCP概述
通信双方建立了TCP连接后,双方就可以相互发送数据了。TCP负责把用户数据(字节流)按照一定格式和长度组成多个数据报进行发送,然后在接到数据报之后分解按顺序重新组装和恢复用户数据。利用TCP传输数据时,数据时以字节的形式进行传输的。客户端和服务端建立连接后,发送数据方需要先将数据转换为字节流,然后将字节流发送到对方。TCP协议主要有以下特点:
- 是面向连接的传输层协议
- 每个TCP连接只能有两个端点,且只能一对一通信
- 通过TCP连接传送数据能够保证报文的完整和准确性
- 数据只能够以字节流的形式传输
- 传输的数据无消息边界
2.在.NET平台TCP应用的工作模式
在.NET平台下开发TCP应用程序,框架提供两种工作方式,①同步工作方式 ②异步工作方式。这里所说的同步工作方式和异步工作方式和线程间的同步并不是一个概念。线程间的同步指的是不同线程或其他共享资源具有先后关联的关系;而同步TCP和异步TCP指的是TCP编程中采用的两种不同的工作方式,即:从执行到方式、接收或监听语句时,程序是否继续往下执行,继续执行的就是异步TCP,如果程序阻塞那就是同步TCP。
与同步工作方式和异步工作方式相对应,利用Socket类开发应用.NET框架也提供了相应的编程方式:分别是同步Socket编程和异步Socket编程。为了简化编程的复杂度,.NET将Socket类进行进一步的封装,提供了两个类:TcpClient类和TcpListener类,这两个类也分别提供同步和异步工作方式的API。
2.1 了解TcpListener和TcpClient
通过前面我们知道:TcpClient类和TcpListener类简化了Socket编程的复杂度,但是要注意:TcpClient和TcpListener这两个类只支持标准协议编程,如果需要编写非标准协议的应用程序,只能使用Socket来实现。
TcpClient类用于提供本机主机和远程主机的连接信息,而TcpListener类则用于监听客户端的请求(这两个类的更多信息可以参考MSDN类库,文中已经给出连接,这里就不在赘述了)。当Socket通信双发建立了连接后,创建了TcpClient对象,就可以使用该对象的GetStream()方法得到NetworkStream对象,然后再利用网络流对象向远程主机发送或接收流数据。
3.解决TCP的无消息边界问题
我们知道网络数据传输是基于流的,在采用TCP通信保证了我们接收和发送数据顺序和完整性,但是在实际的网络传输过程可能会出现发送方和接收方消息不一致的情况。例如:第一次发送的数据为“123456”,第二次发送的数据为“ABCDEF”,有时候可能会出现这种情况:“123456ABCDEF”同时接收了;或者是先接收“123456ABC”,然后在接收“DEF”等情况。之所以出现这种情况是因为:TCP是一种以字节流形式传输的、无消息边界的协议,由于网络中不确定因数的影响,因此不能够保证每个Send方法发送的数据被对应的Recive读取。所以在实际的Socket应用程序开发是必须要考虑消息边界的问题否则就有可能出现数据错误等问题。解决TCP消息边界一般使用下面的三种方式,我们可以根据场景的不同选用不同的方式。
3.1 发送固定长度的消息
这种方式适用于消息长度固定的场景。具体实现时可以使用BinaryReader/BinaryWriter对象每次向网络流,发送/读取一个固定长度的数据即可。例如每次发送一个int类型的32位整数。
TcpClient client = new TcpClient("www.baidu.com", );
NetworkStream m_NetStream = client.GetStream();
BinaryWriter bw = new BinaryWriter(m_NetStream, Encoding.UTF8);
bw.Write();
3.2 将消息长度与消息一起发送
这种方式一般在每次发送消息的前面用4个字节表面本次消息的长度,然后将包含消息长度的消息发送给对方;对方收到消息后,首先从消息的前四个字节读取消息长度,然后根据消息长度值接收发送方发送的数据。这种方法适用于任何场合,在这里我们可以利用BinaryReader和BinaryWriter对象来对NetworkStream进行进一步的封装,当我们使用BinaryWriter对象调用Write(+18重载)方法向网络流写入数据时,该方法会自动计算发出送数据占用的字节数,并使用4(根据发送数据类型)个字节附加到字符串前面;然后另一方使用BinaryReader对象的对应于BinaryWriter对象的Write()方法读取数据时,它会首先读取数据的长度,并自动根据数据前缀读取指定长度的数据。
3.3 使用特殊标记分隔消息
这种方式适用于消息中不包含特殊标记的场合。例如:在每个命令后面添加回车换行(\r\n)符号作为分隔符的场合。如果对于字符串处理,实现这种方法最简便的途径是使用StreamWriter对象和StreamReader对象。发送时使用StreamWriter对象的WriteLine()方法将发送的字符串写入网络流,接收方只需需要调用StreamReader对象的ReadLine()方法将以回车换行符作为分隔符的字符串从网络流中读取即可。
4.同步TCP Socket 示例程序
经过前面知识的积淀,现在我们直接通过创建一个简单的聊天程序来基于同步TCP Socket网络聊天程序,程序的实现比较简单,服务器接收多个客户端连接,客户端和客户端直接通过服务器中转消息达到相互通信的目的。客户端和服务器直接的消息交互使用JSON来进行传递,在这里使用了第三方的JSON库JSON.NET(关于JSON.NET的使用细节参考:JSON.NET使用小结)。下面是程序运行的效果:
运行服务端:
打开多个客户端,在在线列表中选择聊天对象,发送聊天信息:
【转】C# Socket编程(5)使用TCP Socket的更多相关文章
- C# Socket编程(5)使用TCP Socket
TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer) ...
- Windows下C语言的Socket编程例子(TCP和UDP)
原文:Windows下C语言的Socket编程例子(TCP和UDP) 刚刚学windows编程,所以想写学习笔记,这是一个简单的Socket程序例子,开发环境是vc6: 首先是TCP server端: ...
- 《java入门第一季》之Socket编程通信和TCP协议通信图解
Socket编程通信图解原理: TCP协议通信图解
- Socket编程实践(6) --TCP服务端注意事项
僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...
- Windows Socket编程精华《TCP通信服务器》
1.网络中进程之间如何通信? 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问 ...
- python socket 编程之一:编写socket的基本步骤
一.socket 编写server的步骤: 1.第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family ...
- Socket编程基础——面向连接TCP
WinSock是Windows环境下的网络编程接口,它最初是基于Unix环境下的BSD Socket,是一个与网络协议无关的编程接口.WinSock包含两个主要版本,即WinSock1和WinSock ...
- Socket 编程中,TCP 流的结束标志与粘包问题
因为 TCP 本身是无边界的协议,因此它并没有结束标志,也无法分包. socket和文件不一样,从文件中读,读到末尾就到达流的结尾了,所以会返回-1或null,循环结束,但是socket是连接两个主机 ...
- Socket编程:UDP和TCP概论及案例
网络编程的三要素: 1.IP地址 2.端口 3.协议 什么是Socket? Socket就是通信链路的端点称"套接词". 基于TCP协议的Socket网络通信: 用来实现双向安全 ...
随机推荐
- hdu1596 find the safest road - floyd
2017-08-04 14:42:56 writer:pprp 题意: Problem Description XX星球有很多城市,每个城市之间有一条或多条飞行通道,但是并不是所有的路都是很安全的,每 ...
- SpiralOrderTraverse,螺旋遍历二叉树,利用两个栈
问题描述:s型遍历二叉树,或者反s型遍历二叉树 算法分析:层序遍历二叉树只需要一个队列,因为每一层都是从左往右遍历,而s型遍历二叉树就要用两个栈了,因为每次方向相反. public static vo ...
- js:s上次预览,上传图片预览,图片上传预览
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- docker安装脚本
此docker安装脚本为官方提供的,可以从网上下载,此处直接把脚本内容贴上. #!/bin/sh set -e # This script is meant for quick & easy ...
- angular指令详解--自定义指令
自定义指令 directive()这个方法是用来定义指令的: angular.module('myApp', []) .directive('myDirective', function ($time ...
- 一般处理程序ashx中用session存储数据
如果要使用session的话,在handler的代码中添加System.Web.SessionState的引用,并让这个handler继承IRequiresSessionState接口,一定要继承这个 ...
- 六 web爬虫讲解2—urllib库爬虫—基础使用—超时设置—自动模拟http请求
利用python系统自带的urllib库写简单爬虫 urlopen()获取一个URL的html源码read()读出html源码内容decode("utf-8")将字节转化成字符串 ...
- 配置管理puppet
目录: 1.功能 2.服务器 3.管理对应配置文件 4.脚本相关 5.puppet配置相关 6.puppet客户端安装脚本 7.主机配置文件新增节点详细 8.新增文件项目 9.puppet管理命令 ...
- elasticsearch负载均衡节点——客户端节点 node.master: false node.data: false 其他配置和master 数据节点一样
elasticSearch的配置文件中有2个参数:node.master和node.data.这两个参 数搭配使用时,能够帮助提供服务器性能. 数据节点node.master: false node. ...
- java继承的一些问题
如果在父类中,你声明了一个静态变量. 然后你有两个子类继承了这个父类.我们想看看这两个子类调用继承的父类的类变量a是不是同一个值. 这时候注意,我们在子类的时候不能重写static int a = a ...