实现的功能:
本功能是实现局域网下用户端呼叫服务器端,并在服务器端弹出提示框
(PS:我们用主机名实现通信)
需要学习和用到的类:
类名 | 引用 | 作用 |
Thread | using System.Threading | 线程,可以创建并控制线程,设置其优先级并获取其状态最为常用的类 |
Socket | using System,Net.Sockets | 异步通信,能够随时发送数据,并且能够随时接受服务器发送过来的数据,能够判断服务器端或端口网络的连接状态,随时查看与服务器通讯是否通畅 |
IPAddress | using System.Net | 提供了对IP地址的转换、处理等功能 |
IPEndPoint | using System.Net | 应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号 |
Dns | using System.Net | 提供了一系列静态的方法,用于获取提供本地或远程域名等功能 |
Thread类方法:
- Thread.Start():启动线程的执行;
- Thread.Suspend():挂起线程,或者如果线程已挂起,则不起作用;
- Thread.Resume():继续已挂起的线程;
- Thread.Interrupt():中止处于 Wait或者Sleep或者Join 线程状态的线程;
- Thread.Join():阻塞调用线程,直到某个线程终止时为止;
- Thread.Sleep():将当前线程阻塞指定的毫秒数;
- Thread.Abort():以开始终止此线程的过程。如果线程已经在终止,则不能通过Thread.Start()来启动线程。
属性:
IsBackground
- 当在主线程中创建了一个线程,那么该线程的IsBackground默认是设置为FALSE的。
- 当主线程退出的时候,IsBackground=FALSE的线程还会继续执行下去,直到线程执行结束。
- 只有IsBackground=TRUE的线程才会随着主线程的退出而退出。
- 当初始化一个线程,把Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出。
- 原理:只要所有前台线程都终止后,CLR就会对每一个活在的后台线程调用Abort()来彻底终止应用程序。
实例化
Thread threadWatch = new Thread(WatchConnecting);
- Thread是线程,一个线程一般会用来执行某个操作,而这个具体这个操作这是通过一个委托指向某个函数。
- 在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式(ThreadStart),另一种是带参数的启动的方式(ParameterizedThreadStart)。
Socket类方法:
- ------------------相关类--------------------------
- •IPAddress类:包含了一个IP地址
- •IPEndPoint类:包含了一对IP地址和端口号
- --------------------方法们------------------------------
- Socket (): 创建一个Socket
- Bind(): 绑定一个本地的IP和端口号(IPEndPoint)
- Listen(): 让Socket侦听传入的连接尝试,并指定侦听队列容量
- Connect(): 初始化与另一个Socket的连接
- Accept(): 接收连接并返回一个新的socket
- Send(): 输出数据到Socket
- Receive(): 从Socket中读取数据
- Close(): 关闭Socket (销毁连接)
-
–如:
–IPAddress addr = IPAddress.Parse("127.0.0.1");
–IPEndPoint endp = new IPEndPoint(addr, 10001);
服务端先绑定:serverWelcomeSocket.Bind(endp)
客户端再连接:clientSocket.Connect(endp)
Socket通信基本流程图
IPAdress类方法
- Parse ():将IP地址字符串转换为IPAdress实例
- TryParse():确定字符串是否为有效的IP地址
- MapToIPv4():将IPAddress对象映射到IPv4地址
- IsLoopback():指示指定IP是否是回环地址
- GetAddressBytes():以字节数组形式提供IPAddress的副本
- Equals() :比较两个IP地址
IPEndPoint类
我们可以通过2种构造方法来创建IPEndPoint类:
- IPEndPoint(long address, int port)(ipv6)
- IPEndPoint(IPAddress address, int port)(ipv4)
Dns类
- GetHostAddresses():获取指定主机的IP地址,返回一个IPAddress类型的数组。
- GetHostName():获取本机主机名。
实现功能需要两个类,一个服务器端所需要的类(ReceiveOrder)一个是用户所需要的类(Sendorder)
ReceiveOrder类
public class ReceiveOrder
{
Thread threadWatch = null; //负责监听客户端的线程
Socket socketWatch = null; //负责监听客户端的套接字
Socket socConnection = null;//创建一个负责和客户端通信的套接字
public void Receive()
{
bool IsContain = false;
//定义一个套接字用于监听客户端发来的信息 包含3个参数(IP4寻址协议,流式连接,TCP协议)
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//服务端发送信息 需要1个IP地址和端口号
//获取文本框输入的IP地址
//IPAddress ipaddress = IPAddress.Parse(txtIP.Text.Trim());
//将主机名转化为IP地址
IPAddress[] ips = Dns.GetHostAddresses("DESKTOP-RN1CDVF");
string ic = Convert.ToString(ips[1]);
IPAddress ipaddress = IPAddress.Parse(ic);
//将IP地址和端口号绑定到网络节点endpoint上
IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse("1")); //获取文本框上输入的端口号
//监听绑定的网络节点
socketWatch.Bind(endpoint);
//将套接字的监听队列长度限制为20
socketWatch.Listen(20);
//创建一个监听线程
threadWatch = new Thread(WatchConnecting);
//将窗体线程设置为与后台同步
threadWatch.IsBackground = true;
//启动线程
threadWatch.Start();
//启动线程后 txtMsg文本框显示相应提示
}
/// <summary>
/// 监听客户端发来的请求
/// </summary>
private void WatchConnecting()
{
while (true) //持续不断监听客户端发来的请求
{
socConnection = socketWatch.Accept();
ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg);
Thread thr = new Thread(pts);
thr.IsBackground = true;
//启动线程
thr.Start(socConnection);
}
}
/// <summary>
/// 发送信息到客户端的方法
/// </summary>
/// <param name="sendMsg">发送的字符串信息</param>
private void ServerSendMsg(string sendMsg)
{
//将输入的字符串转换成 机器可以识别的字节数组
byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendMsg);
//向客户端发送字节数组信息
socConnection.Send(arrSendMsg);
}
/// <summary>
/// 接收客户端发来的信息
/// </summary>
/// <param name="socketClientPara">客户端套接字对象</param>
private void ServerRecMsg(object socketClientPara)
{
try
{
Socket socketServer = socketClientPara as Socket;
while (true)
{
//创建一个内存缓冲区 其大小为1024*1024字节 即1M
byte[] arrServerRecMsg = new byte[1024 * 1024];
//将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
int length = socketServer.Receive(arrServerRecMsg);
//将机器接受到的字节数组转换为人可以读懂的字符串
string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
MessageBox.Show(strSRecMsg);
}
}
catch (Exception)
{
}
}
private DateTime GetCurrentTime()
{
DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
return currentTime;
}
}
Sendorder类
public class Sendorder
{
//创建 1个客户端套接字 和1个负责监听服务端请求的线程
Socket socketClient = null;
Thread threadClient = null;
public void Send()
{
bool IsContain = false;
//定义一个套字节监听 包含3个参数(IP4寻址协议,流式连接,TCP协议)
socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//需要获取文本框中的IP地址
IPAddress[] ips = Dns.GetHostAddresses("DESKTOP-RN1CDVF");
string ic = Convert.ToString(ips[1]);
IPAddress ipaddress = IPAddress.Parse(ic);
//将获取的ip地址和端口号绑定到网络节点endpoint上
IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse("1"));
//这里客户端套接字连接到网络节点(服务端)用的方法是Connect 而不是Bind
socketClient.Connect(endpoint);
//创建一个线程 用于监听服务端发来的消息
threadClient = new Thread(RecMsg);
//将窗体线程设置为与后台同步
threadClient.IsBackground = true;
//启动线程
threadClient.Start();
ClientSendMsg("你有订单");
}
/// <summary>
/// 接收服务端发来信息的方法
/// </summary>
private void RecMsg()
{
try
{
while (true) //持续监听服务端发来的消息
{
//定义一个1M的内存缓冲区 用于临时性存储接收到的信息
byte[] arrRecMsg = new byte[
1024 * 1024];
//将客户端套接字接收到的数据存入内存缓冲区, 并获取其长度
int length = socketClient.Receive(arrRecMsg);
//将套接字获取到的字节数组转换为人可以看懂的字符串
string strRecMsg = Encoding.UTF8.GetString(arrRecMsg, 0, length);
}
}
catch (Exception)
{
}
}
/// <summary>
/// 发送字符串信息到服务端的方法
/// </summary>
/// <param name="sendMsg">发送的字符串信息</param>
private void ClientSendMsg(string sendMsg)
{
//将输入的内容字符串转换为机器可以识别的字节数组
byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg);
//调用客户端套接字发送字节数组
socketClient.Send(arrClientSendMsg);
}
/// <summary>
/// 获取当前系统时间的方法
/// </summary>
/// <returns>当前时间</returns>
private DateTime GetCurrentTime()
{
DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
return currentTime;
}
}