该博客源著地址https://www.cnblogs.com/sunev/archive/2012/08/05/2604189.html

一、摘要

  总结一下基于C#的TCP传输协议的涉及到的常用方法及同步实现。

二、实验平台

  Visual Studio 2010

三、socket编程的一些常用方法(同步实现)

3.1 命名空间

  需要添加的命名空间

using System.Net;
using System.Net.Socket;

3.2 构造新的socket对象

socket原型:

public socket (AddressFamily addressFamily,SocketType sockettype,ProtocolType protocolType)

(1) AddressFamily 用来指定socket解析地址的寻址方案,Inte.Network标示需要ip版本4的地址,Inte.NetworkV6需要ip版本6的地址;

(2) SocketType 参数指定socket类型,Raw支持基础传输协议访问,Stream支持可靠,双向,基于连接的数据流;

(3) ProtocolType 表示socket支持的网络协议,如常用的TCP和UDP协议。

3.3 定义主机对象
(1) IPEndPoint类

原型:

a)

public IPEndPoint(IPAddress address,int port)  

参数address可以直接填写主机的IP,如"192.168.2.1";

b)

public IPEndPoint(long address,int port)

参数address整型int64如123456,参数port端口int32,如6655。

(2) 利用DNS服务器解析主机,使用Dns.Resolve方法

原型:

public static IPHostEntry Resolve(string hostname)

参数:待解析的主机名称,返回IPHostEntry类值,IPHostEntry为Inte.Net主机地址信息提供容器,该容器提供存有IP地址列表,主机名称等。

(3) Dns.GetHostByName获取本地主机名称

原型:

public static IPHostEntry GetHostByName(string hostname)

(4) GetHostByAddress

原型:

a)

public static IPHostEntry GetHostByAddress(IPAddress address)

参数:IP地址。

b)

public static IPHostEntry GetHostByAddress(string address)

参数:IP地址格式化字符串。

3.4 端口绑定和监听

  同步套接字服务器主机的绑定和端口监听,Socket类的Bind(绑定主机),Listen(监听端口),Accept(接收客户端的连接请求)。

(1) Bind

原型:

public void Bind(EndPoint LocalEP)

参数为主机对象 IPEndPoint

(2) Listen

原型:

public void Listen(int backlog)

参数整型数值,挂起队列最大值

(3) accept

原型:

public socket accept()

返回为套接字对象

3.5 socket的发送和接收方法

(1) 发送数据

a)socket类的send方法

原型一:

public int Send(byte[] buffer)

参数:待发送的字节数组;

原型二:

public int Send(byte[],SocketFlags)

SocketFlags成员列表:

DontRoute不使用路由表发送,

MaxIOVectorLength为发送和接收数据的wsabuf结构数量提供标准值,

None 不对次调用使用标志,

OutOfBand消息的部分发送或接收,

Partial消息的部分发送或接收,

Peek查看传入的消息。

原型三:

public int Send(byte[],int,SocketFlags)

参数二要发送的字节数

原型四:

public int Send(byte[],int,int,SocketFlags)

参数二为Byte[]中开始发送的位置

b) NetWordStream类的Write方法

原型:

public override void write(byte[] buffer,int offset,int size)

参数分别为:字节数组,开始字节位置,总字节数。

(2) 接收数据

a) Socket类Receive方法

原型一:

public int Receive(byte[] buffer) 

原型二:

public int Receive(byte[],SocketFlags)

原型三:

public int Receive(byte[],int,SocketFlags)  

原型四:

public int Receive(byte[],int,int,SocketFlags)

Socket类Receive方法的相关参数可参看Socket类Send方法中的参数。

b) NetworkStream类的Read方法

public override int Read(int byte[] buffer,int offset,int size)

参数可参看NetworkStream类的Write方法。

四、TCP传输协议的同步实现

4.1 服务器端编程的步骤:

(1) 创建套接字;

(2) 绑定套接字到一个IP地址和一个端口上(bind());

(3)将套接字设置为监听模式等待连接请求(listen());

(4)请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

(5)用返回的套接字和客户端进行通信(send()/recv());

(6)返回,等待另一连接请求;

(7)关闭套接字。

服务器端代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text; namespace net
{
class Program
{
static void Main(string[] args)
{
//定义接收数据长度变量
int recv;
//定义接收数据的缓存
byte[] data = new byte[1024];
//定义侦听端口
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 5566);
//定义套接字类型
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接
socket.Bind(ipEnd);
//开始侦听
socket.Listen(10);
//控制台输出侦听状态
Console.Write("Waiting for a client");
//一旦接受连接,创建一个客户端
Socket client = socket.Accept();
//获取客户端的IP和端口
IPEndPoint ipEndClient = (IPEndPoint)client.RemoteEndPoint;
//输出客户端的IP和端口
Console.Write("Connect with {0} at port {1}", ipEndClient.Address, ipEndClient.Port);
//定义待发送字符
string welcome = "Welcome to my server";
//数据类型转换
data = Encoding.ASCII.GetBytes(welcome);
//发送
client.Send(data, data.Length, SocketFlags.None);
while (true)
{
//对data清零
data = new byte[1024];
//获取收到的数据的长度
recv = client.Receive(data);
//如果收到的数据长度为0,则退出
if (recv == 0)
break;
//输出接收到的数据
Console.Write(Encoding.ASCII.GetString(data, 0, recv));
//将接收到的数据再发送出去
client.Send(data, recv, SocketFlags.None);
}
Console.Write("Disconnect form{0}", ipEndClient.Address);
client.Close();
socket.Close();
}
}
}

4.2 客户端编程的步骤:

(1) 创建套接字;

(2) 向服务器发出连接请求(connect());

(3) 和服务器端进行通信(send()/recv());

(4) 关闭套接字。

客户端代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text; namespace client
{
class Program
{
static void Main(string[] args)
{
//定义发送数据缓存
byte[] data = new byte[1024];
//定义字符串,用于控制台输出或输入
string input, stringData;
//定义主机的IP及端口
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEnd = new IPEndPoint(ip, 5566);
//定义套接字类型
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//尝试连接
try
{
socket.Connect(ipEnd);
}
//异常处理
catch (SocketException e)
{
Console.Write("Fail to connect server");
Console.Write(e.ToString());
return;
}
//定义接收数据的长度
int recv = socket.Receive(data);
//将接收的数据转换成字符串
stringData = Encoding.ASCII.GetString(data, 0, recv);
//控制台输出接收到的数据
Console.Write(stringData); //定义从键盘接收到的字符串
input = Console.ReadLine(); //将从键盘获取的字符串转换成整型数据并存储在数组中
data = Encoding.ASCII.GetBytes(input);
//发送该数组
socket.Send(data, data.Length, SocketFlags.None); while (true)
{
// //如果字符串是"exit",退出while循环
if (input == "exit")
{
break;
}
//对data清零
data = new byte[1024];
//定义接收到的数据的长度
recv = socket.Receive(data);
//将接收到的数据转换为字符串
stringData = Encoding.ASCII.GetString(data, 0, recv);
//控制台输出字符串
Console.Write(stringData);
//发送收到的数据
socket.Send(data, recv, 0); }
Console.Write("disconnect from server");
socket.Shutdown(SocketShutdown.Both);
socket.Close();
} }
}

  上述代码实现了,当连接建立之后,客户端向服务器端发送键盘输入的字符,服务器端收到字符后,显示在控制台并发送给客户端,客户端收到字符后,显示在控制台并再次发送给服务器端,如此循环。

五、实验结果

  先后运行服务器端程序和客户端程序,控制台界面如下:

图1 服务器端控制台

  当连接建立后,服务器端控制台显示等待客户端的状态"Waiting for a client",并打印出连接信息。

图2 客户端控制台

  当连接建立后,客户端收到来自服务器端发送的字符串"Welcome to my server"。

  之后,客户端通过键盘发送数据,二者循环接收并发送,控制台分别如下:

图3 服务器控制台

图4 客户端控制台

六、几点说明

6.1 传输速度

  (1) 增大发送和接收的数组可提升传输速度,即增加一次实际发送数据的数量可以提高传输速度,但数组中数据的个数也不能一味的增大。需要说明的,由于地层MIT的限制,底层具体实现的时候每次发送的数据仍是不超过1510个的。

  (2) 将控制台界面最小化后,速度也会有翻倍的提升。

6.2 MFC的转换

  为了使传输协议更有可观性和使用性,通常做成MFC的样式,具体的使用已在"基于TCP协议的网络摄像头的设计与实现"应用。

最新文章

  1. Owin:“System.Reflection.TargetInvocationException”类型的未经处理的异常在 mscorlib.dll 中发生
  2. CentOS 6.5 Nginx 配置
  3. vue.js 2.0开发(4)
  4. [MAC]用beamoff给VMware的Mac OS X 10.10.x加速
  5. java中图片文件的传输及显示(Socket以及ServerSocket演示)
  6. Alpha阶段个人总结
  7. C#_拆箱跟装箱
  8. SO_REUSEADDR 和 SO_REUSEPORT
  9. build.gradle(Project) 和 build.gradle(Module) 的区别
  10. DataTable转CSV
  11. Java [Leetcode 88]CMerge Sorted Array
  12. 后台启动mysql ,redis
  13. WEB安全实战(五)XSS 攻击的第二种解决方式(推荐)
  14. Redis学习笔记一
  15. Linux常用的命令以及配置
  16. javaScript函数节流与函数防抖
  17. Mouse Without Borders软件,主要功能备忘录
  18. MySQL 各种主流 SQLServer 迁移到 MySQL 工具对比
  19. [Java]MyBatis框架
  20. 理解webpack4.splitChunks之chunks

热门文章

  1. linux安装命令行 图形查看 CPU温度 传感器-20191218
  2. Mysql 数据库基本操作
  3. STM32F7系列时钟相关问题:HSE模式配置(旁路模式、非旁路模式
  4. 企业定制CRM系统的5步流程
  5. Java安全之Cas反序列化漏洞分析
  6. TPS和响应时间之间是什么关系
  7. 『动善时』JMeter基础 — 36、JMeter接口关联【正则表达式提取器】
  8. TVM量化小结手册
  9. CUDA运行时 Runtime(四)
  10. 「题解」agc031_e Snuke the Phantom Thief