C#网络通信系列学习笔记
第一章、C#最简单的控制台网络通信
前言
网络通信是很多码农入职的第一课,也是毕业设计、课程设计上使用的重灾区,可以说不会网络通信的码农不是一个好码农。
通过这篇文章,你将学习如何使用C#Socket库来进行通信。ok,我们先从最简单的控制台开始。
一、Socket是什么?
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
Socket的英文原义是“孔”或“插座”。作为BSD UNIX的 进程通信机制,取后一种意思。通常也称作" 套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的 主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。——C#Socket通信原理(基础篇)
也就是说
- 网络上的两台主机要想完成通信需要两边都做好准备,这个准备工作可以由Socket来完成
- 一个socket需要占用一个本地计算机的端口
- 一台计算机上的不同软件可以与不同的远程计算机通信,他们之间是互不干扰的
- 一台计算机上的多个软件可能在与远程同一台计算机进行通信,但是它们用的端口是不同的,也就是两台主机之间可能存在着多个连接,尽管连接的对象都是一样的
- 我可以客户端和服务端都在一台主机上,自己跟自己玩~
另外,网络通信是分为客户端模式和服务器模式的
客户端模式:我需要连接到一个指定的IP地址和端口号,因此我必须知道对方的IP地址和端口号
服务器模式:我不知道谁会连接我,因此我绑定一个固定端口随时监听它,等待客户端的连接请求。
二、最简单的控制台通信
1.客户端
代码如下(示例):
using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
//建立一个socket对象需要指定socket类型、协议类型等参数
//这里第一个参数使用IPv4版本的地址,第二个参数指可靠稳定的字节流socket,第三个参数是采用TCP\协议
Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ServerIP = IPAddress.Parse("127.0.0.1");//将ip地址字符串转化为ip地址对象,这里以本地作为服务器
//在Internet中,TCP/IP使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;
//端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,
//在.NET框架中正是由EndPoint类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息
IPEndPoint endPoint = new IPEndPoint(ServerIP, 20000);//端口号可以自己设置,不要与其他程序冲突,与服务端保持一致就可以
ClientSocket.Connect(endPoint);//连接到这个终结点,这里要注意如果连接不上是会报错的哦
string MyMsg = "我要发送的数据";
byte[] MsgByteArray = Encoding.UTF8.GetBytes(MyMsg);//文字信息是不能直接发送的,需要先转化为字节流
int SendNum = ClientSocket.Send(MsgByteArray);//这里使用最简单的一种重载,直接发送字节数组
if (SendNum <= 0)
Console.WriteLine("发送失败");
else
Console.WriteLine("发送成功");
ClientSocket.Blocking = true;//设置为阻塞模式,否则可能接收不到数据
byte[] ReceiveMsgByteArray = new byte[1024];
ClientSocket.Receive(ReceiveMsgByteArray);//接收返回的信息
Console.WriteLine(Encoding.UTF8.GetString(ReceiveMsgByteArray));//将收到的字节流转换回字符串并打印
Console.ReadLine();//这里读取一行输入,防止程序执行完闪退
ClientSocket.Close();//关闭socket连接
}
}
}
在这个例子中我们只让它发送一条消息并接收一条消息就可以了,当然现在还是没办法胜任这个任务的,因为根本打不开连接呀~
接下来我们在写一个服务端的控制台程序来跟它互动
2.服务端
代码如下(示例):
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//IPAddress kehuip = IPAddress.Parse("0.0.0.0");
IPAddress ClientIP = IPAddress.Any;//允许哪个地址连接我,这个值表示任意,与上面的表示形式相同
Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(ClientIP, 20000);//监听20000端口,客户端连接的时候就需要连接这个端口号
socketwatch.Bind(endPoint);//绑定这个终结点
socketwatch.Listen(3);//开始监听,参数表示最大允许几台主机连接我
Console.WriteLine("开始监听 端口号:20000 \r\n");
Socket ClientSocket = socketwatch.Accept();//如果有客户端连接,就会返回这个客户端的sockeet对象
ClientSocket.Blocking = true;
byte[] ReceiveMsgByteArray = new byte[1024];
ClientSocket.Receive(ReceiveMsgByteArray);//接收返回的信息
Console.WriteLine(Encoding.UTF8.GetString(ReceiveMsgByteArray));//将收到的字节流转换回字符串并打印
ClientSocket.Send(Encoding.UTF8.GetBytes("我收到了你的消息"));//礼尚往来,给客户端回一句
Console.ReadLine();//这里读取一行输入,防止程序执行完闪退
ClientSocket.Close();//关闭socket连接
}
}
}
3.执行
先运行服务端的控制台程序
在跑上客户端控制台
啪的一下很快啊,都没反应过来两边就都收到了并且运行结束了,我们给它加个延时直观一点。
服务端加上这两行断点处的代码
客户端加上这两行,按上述步骤再次执行