TCP/IP网络编程
TCP/IP(Transmission Control Protocol/Internet Protocol)的简写,中文译名为传输控制协议/网际协议,又叫网络通讯协议,这个协议是是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。
TCP/IP 是供已连接因特网的计算机进行通信的通信协议。
TCP/IP 定义了设备(并非只有计算机)如何连入因特网,以及数据如何在它们之间传输的标准。
IP(Internet Protocol)因特网协议。从这个名称我们就可以知道IP协议的重要性。在现实生活中,我们进行货物运输时都是把货物包装成一个个的纸箱或者是集装箱之后才进行运输,在网络世界中各种信息也是通过类似的方式进行传输的。IP协议规定了数据传输时的基本单元和格式。如果比作货物运输,IP协议规定了货物打包时的包装箱尺寸和包装的程序。 除了这些以外,IP协议还定义了数据包的递交办法和路由选择。同样用货物运输做比喻,IP协议规定了货物的运输方法和运输路线。
我们已经知道了IP协议很重要,IP协议已经规定了数据传输的主要内容,那TCP(Transmission Control Protocol)协议是做什么的呢?不知大家发现没有,在IP协议中定义的传输是单向的,也就是说发出去的货物对方有没有收到我们是不知道的。就好像8毛钱一份的平信一样。那对于重要的信件我们要寄挂号信怎么办呢?TCP协议就是帮我们寄“挂号信”的。TCP协议提供了可靠的面向对象的数据流传输服务的规则和约定。简单的说在TCP模式中,对方发一个数据包给你,你要发一个确认数据包给对方。通过这种确认来提供可靠性。
UDP与TCP位于同一层,但它不管数据包的顺序、错误或重发。因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询---应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。使用UDP的服务包括NTP(网络时间协议)和DNS(DNS也使用TCP)。
欺骗UDP包比欺骗TCP包更容易,因为UDP没有建立初始化连接(也可以称为握手)(因为在两个系统间没有虚电路),也就是说,与UDP相关的服务面临着更大的危险。
TCP和UDP服务通常有一个客户/服务器的关系,例如,一个Telnet服务进程开始在系统上处于空闲状态,等待着连接。用户使用Telnet客户程序与服务进程建立一个连接。客户程序向服务进程写入信息,服务进程读出信息并发出响应,客户程序读出响应并向用户报告。因而,这个连接是双工的,可以用来进行读写。
两个系统间的多重Telnet连接是如何相互确认并协调一致呢?TCP或UDP连接唯一地使用每个信息中的如下四项进行确认:
1.源IP地址 发送包的IP地址。
2.目的IP地址 接收包的IP地址。
3.源端口 源系统上的连接的端口。
4.目的端口 目的系统上的连接的端口。
端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程通常使用一个固定的端口,例如,SMTP使用25。这些端口号是‘广为人知’的,因为在建立与特定的主机或服务的连接时,需要这些地址和目的地址进行通讯。
在.net中,我们用TCPClient和TCPListener类来实现点对点通讯,这两个命名空间位于此System.Net.Sockets
TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求。可使用 TcpClient 或 Socket 来连接 TcpListener。可使用 IPEndPoint、本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener。
TcpClient 类提供了一些简单的方法,用于在同步阻止模式下通过网络来连接、发送和接收流数据。
一服务端一客户端通讯
服务端Code
需要引入的命名空间:
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
需要定义的字段:
Thread thr = null;
StreamReader sr;
StreamWriter sw;
监控单击事件按钮对应方法:
private void Con_BUT_Click(object sender, EventArgs e)
{
//启动一个线程,用来TCP/IP服务端监听
thr = new Thread(new ThreadStart(GetText));
thr.Start();
}
服务客户端一对一
public void GetText()
{
IPAddress IP = IPAddress.Parse(IP_TB.Text);
TcpListener server = new TcpListener(IP, int.Parse(Port_TB.Text));
server.Start(); //开始监听
TcpClient client = server.AcceptTcpClient();
NetworkStream stream = client.GetStream();
sr = new StreamReader(stream);
sw = new StreamWriter(stream);
try
{
while (true)
{
writestring("客户端说:" + sr.ReadLine());
}
}
catch
{
client.Close();
}
}
向Old_Tb中写聊天记录
void writestring(string s)
{
Old_TB.Text +=DateTime .Now.ToString("yy/MM/dd hh:mm:ss")+ s;
Old_TB.Text += "\r\n";
}
客户端Code
需要引入的命名空间:
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
需要定义的字段:
Thread thr = null;
NetworkStream stream;
StreamReader sr;
StreamWriter sw;
连接按钮单击事件对应方法:
private void Con_BUT_Click(object sender, EventArgs e)
{
//启动一个线程,用来连接TCP/IP服务
thr = new Thread(new ThreadStart(ReadServer));
thr.Start(); }
连接服务端方法:
void ReadServer()
{
TcpClient TC = new TcpClient(IP_TB.Text, int.Parse(Port_TB.Text));
stream = TC.GetStream();
sr = new StreamReader(stream);
try
{
while (true)
{
writestring("服务端说:" + sr.ReadLine());
}
}
catch
{
TC.Close();
}
}
写发送和收到信息的方法:
void writestring(string s)
{
Old_TB.Text += s;
Old_TB.Text += "\r\n";
}
写发送方的方法
private void Send_But_Click(object sender, EventArgs e)
{
sw = new StreamWriter(stream);
string msg = New_TB.Text;
sw.WriteLine(msg);
sw.Flush();
writestring("客户端说:" + New_TB.Text);
}
一服务端多客户端通讯
服务端UI同上
服务端Code
需要引入的命名空间:
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
监控单击事件按钮对应方法:
private void Con_BUT_Click(object sender, EventArgs e)
{
//启动一个线程,用来TCP/IP服务端监听
thr = new Thread(new ThreadStart(GetText));
thr.Start();
}
public void GetText()
{
IPAddress IP = IPAddress.Parse(IP_TB .Text);
TcpListener server = new TcpListener(IP, int.Parse(Port_TB.Text));
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
TcpClient client = server.AcceptTcpClient();
NetworkStream NetStr = client.GetStream();
int i = 0;
while ((i = NetStr.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.UTF8.GetString(bytes);
writestring("客户端说:" + data);
data = New_TB.Text;
byte[] msg = System.Text.Encoding.UTF8.GetBytes(data);
NetStr.Write(msg, 0, msg.Length);
writestring("服务端说:" + data);;
}
client.Close();
}
}
向Old_Tb中写聊天记录
void writestring(string s)
{
Old_TB.Text +=DateTime .Now.ToString("yy/MM/dd hh:mm:ss")+ s;
Old_TB.Text += "\r\n";
}
客户端Code
需要引入的命名空间:
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
写发送和收到信息的方法:
void writestring(string s)
{
Old_TB.Text += s;
Old_TB.Text += "\r\n";
}
写发送方的方法
if (New_TB.Text.Trim().Length > 0)
{
TcpClient TC = new TcpClient(IP_TB.Text, int.Parse(Port_TB.Text));
byte[] data = Encoding.UTF8.GetBytes(New_TB.Text);
NetworkStream NetStr = TC.GetStream();
NetStr.Write(data, 0, data.Length);
writestring("客户端说:" + New_TB.Text);
New_TB.Clear();
Byte[] newdate = new Byte[256];
int len = NetStr.Read(newdate, 0, newdate.Length);
writestring("服务端说:" + Encoding.UTF8.GetString(newdate));
NetStr.Close();
TC.Close();
}
UDP/IP通讯
服务端Code
监控按钮
thr = new Thread(new ThreadStart(UDPMethod));
thr.Start();
void UDPMethod()
{
UdpClient sender = new UdpClient(int.Parse(Port_TB.Text));
IPEndPoint endpoint = null;
while (true)
{
byte[] bytes = sender.Receive(ref endpoint);
writestring("UDP:" + Encoding.UTF8.GetString(bytes));
}
}
客户端Code
发送按钮
UDPMethod();
void UDPMethod()
{
UdpClient sender = new UdpClient();
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(IP_TB.Text), int.Parse(Port_TB.Text));
byte[] bytes = Encoding.UTF8.GetBytes(New_TB.Text);
sender.Send(bytes, bytes.Length, endpoint);
writestring("客户端:"+New_TB .Text );
}
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524