TCP、UDP、Socket 通信(原)
说明:本随笔主要演示自己给自己发送消息例子,分别使用了TCP协议、UDP协议以及socket套接字通信。使用socket套接字了模拟TCP、UDP通信实现原理。其中有些源码都来自《C#高级编程 第7版》,并附加了自己的理解,有的也进行了一些简单的拓展。
第一次原创随笔,很多地方可能考虑不周或理解有误,希望大家留言指正,与大家共同进步。也希望大家不喜勿喷,给点鼓励还是比较好的~~ 闲话少说,进入主题!
一、TCP 类
TCP是基于连接的一种通信模式,我们需要创建客户端与服务器端来进行通信。在客户端读取文件,并将文件内容发送到服务器端进行显示。
客户端:
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO; namespace TcpSender
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void btnSend_Click(object sender, EventArgs e)
{
TcpClient tcpClient = new TcpClient("127.0.0.1",); // 配置主机号及端口 127.0.0.1 2112
NetworkStream nws = tcpClient.GetStream(); // 获取连接流
string path = txbFile.Text; // 配置文件路径
FileStream fs = new FileStream(path, FileMode.Open);
int data = fs.ReadByte(); while (data != -)
{
nws.WriteByte((byte)data);
data = fs.ReadByte();
}
fs.Close();
nws.Close();
tcpClient.Close();
}
}
}
服务器:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Windows.Forms; namespace TcpReceiver
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Thread thread = new Thread(new ThreadStart(Listen)); // 防止主线程在监听到请求之前处于卡死状态
thread.Start();
} // 监听功能
public void Listen()
{
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
Int32 port = ;
TcpListener tcpListener = new TcpListener(localAddr, port); // 也可以仅绑定端口,因为发送者与接收者均是本地
tcpListener.Start(); while (true) // 持续监听
{
TcpClient tcpClient = tcpListener.AcceptTcpClient(); // 监听到请求前处于阻塞状态
NetworkStream nws = tcpClient.GetStream(); // 获取监听流 StreamReader sr = new StreamReader(nws, System.Text.Encoding.UTF8);
string content = sr.ReadToEnd(); // ★★★ very important ★★★
Invoke(new Action<string>(UpdateDisplay), new object[] { content }); // 该线程拥有用户界面的句柄,因此无需从后台线程直接访问对话框
tcpClient.Close();
}
// tcpListener.Stop();
} // 将接收到内容显示到控件中
public void UpdateDisplay(string text)
{
txbContent.Clear();
txbContent.Text = text;
}
}
}
运行效果图:

客户端

服务器
二、UDP
UDP是一个无连接的协议,因此可以在一个程序中实现收发消息。
情形1:使用同一个 UdpClient 实例实现收发消息
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.IO; namespace UDPSender
{
class Program
{
static void Main(string[] args)
{
#region 模拟自己发送自己 使用UDPClient(通过)
UdpClient client = new UdpClient(); //相当于给socket实例指定端口,参见socket模拟UDP实现原理(后续代码)
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), ); // 服务器网址及端口 Console.WriteLine("Type in what you want to send :");
string sendMsg = Console.ReadLine();
byte[] sendBytes = Encoding.ASCII.GetBytes(sendMsg);
client.Send(sendBytes, sendBytes.Length, iep); //将消息推送到 127.0.0.1:11000 byte[] rcvBytes = client.Receive(ref iep); // 接收127.0.0.1:11000 端口消息,非连接的消息需要缓存存放
Console.WriteLine("Received the following message:");
string rcvMessage = Encoding.ASCII.GetString(rcvBytes, , rcvBytes.Length);
Console.WriteLine(rcvMessage);
Console.ReadKey();
#endregion
}
}
}
情形2:使用一个 UdpClient 实例发送消息, 使用另一个 UdpClient 实例接收消息
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.IO; namespace UDPSender
{
class Program
{
static void Main(string[] args)
{
#region 模拟自己发送自己 使用UDPClient(通过)
UdpClient client = new UdpClient(); // 没有为socket指定端口,则在client.Send()时,系统默认为socket分配一个端口,参见Socket模拟UDP(后续代码)
// IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
UdpClient server = new UdpClient(); // 在客户端发送之前确保服务器已经进行端口绑定,为客户端发送的消息创建载体 IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), ); // 192.168.106.231 服务器网址及端口 Console.WriteLine("Type in what you want to send :");
string sendMsg = Console.ReadLine();
byte[] sendBytes = Encoding.ASCII.GetBytes(sendMsg);
client.Send(sendBytes, sendBytes.Length, iep); // 将消息推送到 127.0.0.1:11000 byte[] rcvBytes = server.Receive(ref iep); // 接收127.0.0.1:11000 端口消息,也可以使用 remote 端点,表示接收所有端口消息
Console.WriteLine("Received the following message:");
string rcvMessage = Encoding.ASCII.GetString(rcvBytes, , rcvBytes.Length);
Console.WriteLine(rcvMessage);
Console.ReadKey();
#endregion
}
}
}
运行效果图:

三、Socket 通信
TCP、UDP 底层通信都是通过 socket 套接字实现。
1、模拟 TCP 通信实现
客户端:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text; namespace SocketSender
{
// 使用socket类模拟TCP发送原理
class Program
{
static void Main(string[] args)
{
byte[] ReceiveBytes = new byte[];
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), ); // 创建远程端点 Console.WriteLine("Starting: Creating Socket Object ");
while (true)
{
// 创建socket对象
Socket SocketSender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 连接远程端点
SocketSender.Connect(ipEndPoint); // 连接到远程端点,如果服务器端没有响应,则此处会挂起。若超时,则抛出远程服务器拒绝的异常。 Console.WriteLine("Successfully Connected to {0}",SocketSender.RemoteEndPoint); Console.WriteLine("Input the Message you want to send :");
string SendingMessage = Console.ReadLine();
byte[] ForwardMessage = Encoding.ASCII.GetBytes(SendingMessage + "[FINAL]"); // 发送消息
SocketSender.Send(ForwardMessage); // 接收从服务器传回相应消息,因为是基于连接的,因此使用同一个socket实例直接接收即可
int TotalBytesReceived = SocketSender.Receive(ReceiveBytes); // 打印输出接收到的消息
Console.WriteLine("Message Provided By Server: {0}", Encoding.ASCII.GetString(ReceiveBytes, , TotalBytesReceived));
Console.WriteLine(Environment.NewLine);
SocketSender.Shutdown(SocketShutdown.Both); // 关闭该socket的发送和接收功能
SocketSender.Close();
}
//Console.ReadKey();
}
}
}
服务器端:
using System;
using System.Text;
using System.Net;
using System.Net.Sockets; namespace SocketReceiver
{
// 使用socket模拟TCP接收原理
class Program
{
static void Main(string[] args)
{
// 本实例是一个基于连接的socket通信,模拟 TCPClient 进行通信
Console.WriteLine("Starting: Creating Socket object");
Socket Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Listener.Bind(new IPEndPoint(IPAddress.Any, )); // 创建了基于本机IP地址的,端口号为任意值的,可用于所有网络接口(网线、电话线及其他形式网络接口)的绑定
Listener.Listen(); // 挂起连接队列的最大长度 while (true)
{
Console.WriteLine("Waiting for connetion on port 2112 ");
Socket socket = Listener.Accept(); // 若无socket,则处于阻塞状态,等待有效的socket实例
string ReceiveValue = string.Empty; while (true)
{
byte[] ReceivedByte = new byte[]; // 缓存区
int NumBytes = socket.Receive(ReceivedByte); // 接收到的是二进制数据,将接收到的数据放入到缓存中。也可以直接读到流中,使用 Stream stream = new networkstream(socket)
Console.WriteLine("Receiving . . .");
ReceiveValue += Encoding.ASCII.GetString(ReceivedByte, , NumBytes);
if (ReceiveValue.IndexOf("[FINAL]") > -)
{
break;
}
}
Console.WriteLine("Received Value: {0}", ReceiveValue);
Console.WriteLine(Environment.NewLine);
string ReplyValue = "Message successfully Received.";
byte[] ReplyByte = Encoding.ASCII.GetBytes(ReplyValue);
socket.Send(ReplyByte); // 发送的是二进制数据 // 对于面向连接的协议,建议先调用 Shutdown,然后再调用 Close。 这可以确保在已连接的套接字关闭之前,已发送和接收该套接字上的所有数据。
socket.Shutdown(SocketShutdown.Both); // 关闭该socket的关闭和接收功能
socket.Close();
}
// Listener.Close();
}
}
}
运行效果图:

客户端

服务器端
说明:基于链接的通信,应先启动服务器端程序进行监听,后启动客户端程序。否则客户端在尝试连接时,没有服务器进行相应,尝试一定的时间后,若一直无响应,则抛出远程主机拒绝的异常。
2、模拟 UDP 通信实现
不基于连接的通信,只需要一个程序端即可。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.IO; namespace UDPSender
{
class Program
{
static void Main(string[] args)
{
#region 模拟自己发送给自己,使用socket模拟UDP实现原理(通过) // Server
Thread server = new Thread(new ThreadStart(ReceiveServer));
server.Start(); // ★★★确保服务端已建立网络监听★★★
Thread.Sleep(); // Client
IPHostEntry ipHostEntry = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddress = ipHostEntry.AddressList[];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, ); while (true)
{
// UDP 的socket类型不支持stream
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//socket.Bind(ipEndPoint);
socket.Connect(ipEndPoint); // 若在此之前不给socket手动绑定一个端口,则程序会在此时默认给socket随机绑定一个端口
Console.WriteLine("Type in what you want to send:");
string SendString = Console.ReadLine();
byte[] SendBytes = Encoding.Default.GetBytes(SendString);
//Thread.Sleep(3000);
socket.Send(SendBytes);
// 网络接收有延时,因此需要等待服务器进行接收
socket.Close();//等待 timeout 秒以发送所有剩余数据,然后关闭该套接字。
// 等同于socket.Close(100) 的效果
//Thread.Sleep(100);
//socket.Close(); }
#endregion
} public static void ReceiveServer()
{
IPHostEntry ipHostEntry = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddress = ipHostEntry.AddressList[];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, ); #region 使用缓存接收数据
// Receive Message
Socket socketListen = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // set the protocol
socketListen.Bind(ipEndPoint); // binding to the local point which need to be listened try
{
// UDP 协议不需要监听,直接接收消息即可
//socketListen.Listen(5); // 最多监听到5个队列的请求
while (true)
{
string result = string.Empty;
if (socketListen.Available < ) // 判断是否有数据,若没有数据而直接进行receive,则会使线程阻塞等待数据的到来。return 无:0 有:>0
{
Thread.Sleep();
}
else
{
byte[] data = new byte[];
int NumBytes = socketListen.Receive(data); // 如果网络监听不到数据,则该语句会使线程处于阻塞状态而等待消息,因此要添加判断语句判断数据是否有效
Console.WriteLine("Receiving..");
if (NumBytes > )
{
result = Encoding.Default.GetString(data, , NumBytes);
Console.WriteLine("Server Received the follow message:");
Console.WriteLine(result);
Console.WriteLine(Environment.NewLine);
//Thread.Sleep(50000);
}
}
}
}
catch (SocketException e)
{
string a = e.ErrorCode.ToString();
Console.WriteLine(e.Message + e.ErrorCode);
}
#endregion
}
}
}
运行效果图:

注意:对于非连接的通信,在服务器端socket绑定端口(Bind()方法,而非Receive()方法,注意区分)之前,若客户端发送了消息A,则在服务器端口绑定后收不到该消息A,只能收到在绑定端口后客户端发送来的消息!
TCP、UDP、Socket 通信(原)的更多相关文章
- 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1
		
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
 - 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.2
		
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
 - 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.0.1
		
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
 - TCP/UDP简易通信
		
TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的 ...
 - 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.3
		
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
 - 【转】TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端
		
[转]TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP ...
 - TCP&UDP&Socket讲解(上)
		
这两天我将整理TCP&UDP&Socket,大约花大家10-15分钟之间,希望本篇文章让大家对TCP使用的理解提高一个层次. 建议大家拿出纸和笔,画一下!!! 一.TCP 1. TCP ...
 - TCP/UDP,SOCKET,HTTP,FTP 简析
		
(一)TCP/UDP,SOCKET,HTTP,FTP简析 TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层: 网络层:IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议 传 ...
 - TCP UDP socket http webSocket 之间的关系
		
---恢复内容开始--- OSI&TCP/IP模型 要弄清tcp udp socket http websocket之间的关系,首先要知道经典的OSI七层模型,与之对应的是TCP/IP的四层模 ...
 - Bash Shell 下打开一个TCP / UDP SOCKET
		
Bash Shell 下打开一个TCP / UDP SOCKET http://jingyan.baidu.com/article/636f38bb6166c3d6b84610d1.html
 
随机推荐
- 安装多个PHP环境会导致phpinfo和php -v中查看到的PHP版本不一致
			
以前在上一个公司用的是集成环境wamp,PHP版本是5.5.后面换了一个公司,项目用的是PHP版本是5.2.今天想打开以前的项目想优化一下,发现pdo_mysql.dll扩展无法加载,于是想看看是不是 ...
 - 带双反斜杠的Json数据至单反斜杠的Json数据处理
			
假如你光看标题,你只能哦呵呵了!我也看不懂.还是先描述下问题吧.这里是使用微信接口返回了一些数据.因为该串数据包含html标签所以TX是对该串数据进行了编码的.所有的数据是通过Unicode编码的,然 ...
 - 通过反射获取及调用方法(Method)
			
1.获取方法使用反射获取某一个类中的方法,步骤:①找到获取方法所在类的字节码对象②找到需要被获取的方法 Class类中常用方法: public Method[] getMethods():获取包括自身 ...
 - FZU 2138——久违的月赛之一——————【贪心】
			
久违的月赛之一 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Stat ...
 - [转]微信小程序开发踩坑记录
			
本文转自:http://www.cnblogs.com/NKnife/p/6283605.html 1.由于小程序wx.request()方法是异步的,在app.js执行ajax后,各分页加载app. ...
 - 利用WebBrowser控件实现百度自动搜索
			
(1)新建一个MFC对话框项目 (2)对话框中添加WebBrower控件,添加方法:点击菜单栏工具->选择工具箱项->在弹出的选择工具箱项对话框选择COM组件->Microsoft ...
 - MySQL批量插入多条数据方便测试
			
批量插入流程 数据库字段 delimiter create procedure doinsert3() begin declare i int; declare j int; ; ; ) do ins ...
 - javaweb之EL自定义函数
			
1.什么是EL自定义函数 EL自定义函数是在EL表达式中调用的某个java类的静态方法,这个静态方法需在web应用程序中进行配置才可以被EL表达式调用.EL自定义函数可以扩展EL表达式的功能,让EL表 ...
 - JavaScript之parseInt()数值转换常被忽略的问题
			
使用parseInt()你可以从字符串中获取数值,该方法接受另一个基数参数,这经常省略,但不应该.当字符串以”0″开头的时候就有可能会出问题,例如,部分时间进入表单域,在ECMAScript 3中,开 ...
 - vim命令“=”、“d”、“y”的用法(结合光标移动命令,一些场合会非常方便)
			
vim有许多命令,网上搜有一堆贴子.文章列举出各种功能的命令. 对于“=”.“d”.“y”,我在无意中发现了它们所具有的相同的一些用法,先举以下三个例子: =nG dnG ynG 其中,n为行号.注意 ...