C#应用实训|任务1 服务器端功能实现
发布者:唯众
布时间:2020-12-21 13:41:49
点击量:
任务描述
服务器端创建连接后,要实现客户端的信息监控,当客户端发送“报警”信息后,服务器端接收到信息要进行相应的“出警”处理,当客户端请求“撤消报警”后,服务器端接收到信息后要进行相应的“撤消警告”处理。
知识引入
- IP地址
Internet通过网络将计算机连接在一起,每一台计算机都有自己的一个地址,信息在网络中传输遵循网络传输协议TCP/IP协议,按照TCP/IP协议,IP地址由一组二进制数组成,IP地址包括IPV4和IPV6,分别由32位和64位二进制数组成,目前使用较多的为IPV4地址,为方便使用,IP地址经常使用十进制数来描述,每8位二进制数转换成一个十进制数,中间用“.”分隔。如:202.145.36.126。C#中System.Net命名空间为网络编程提供支持类,System.Net.Sockets命名空间为Socket编程提供支持类。
- IPAddress 类
功能:提供主机的IP地址及相关信息。
- IPHostEntry类
功能:提供主机的IP地址、主机名及别名。
主要属性:
AddressList:返回IPAddress[ ],获取或设置与主机关联的IP地址列表。
HostName:返回string[ ],获取或设置主机的DNS名称。
- IPEndPoint类
功能:将网络端点表示为IP地址和端口号。通过IP地址和端口号的组合,构造主机的连接点。
主要属性:
Address:获取或设置终结点IP地址。
AddressFamily:获取网络协议(IP)地址族。AddressFamily.InterNetwork表示此IP为IPv4,
AddressFamily.InterNetworkV6表示此地址为IPv6类型。
Port:获取或设置终结点的端口号。
- Dns 类
功能:提供简单的域名解析功能。
主要属性:
GetHostEntry:将主机名或IP地址解析为IPHostEntry实例。
【
例6-1】
输出本机IP地址及主机名。
新建控制台项目IPGet,编写代码如下:
namespace IPGet
{
class Program
{
static void Main(string[] args)
{
string hostName = Dns.GetHostName();
IPHostEntry localhost = Dns.GetHostEntry(hostName);
string ip = "";
for (int i = 0; i < localhost.AddressList.Length; i++)
{
if (localhost.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
ip = localhost.AddressList[i].ToString();
}
}
Console.WriteLine("hostName:"+hostName);
Console.WriteLine("localIp:" + ip);
}
}
}
- 端口
在网络连接中,端口分为物理端口和逻辑端口,物理端口指计算机硬件的I/O端口,逻辑端口指逻辑意义上用于区分服务的端口,如TCP/IP协议中的服务端口,端口号的范围从0到65535。每一个网络连接都需要一个端口号,一般来说,每个端口都对应着一种应用程序。要建立客户机与服务器之间的连接通信,必须选择一个端口进行连接,端口号0-1023是标准的Internet协议保留端口,用户创建程序自定义端口号范围一般为8000-16000。
- Socket套接字
Socket是基于TCP/IP的编程接口,是种网络通信机制,socket的英文原义是“孔”或“插座”。作为进程通信机制,通常也称作“套接字”,用于描述IP地址和端口。Socket是基于连接的通信,在通信开始前通信双方通过确定身份(IP地址和端口)建立连接通道,然后通过连接通道传送信息。通信结束后关闭连接。
Socket类
构造方法:
public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType)
addressFamily:指定 Socket 使用的寻址方案
socketType:指定 Socket 的类型
protocolType:指定 Socket 使用的协议
例:Socket SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
实例方法:
Socket.Send :从数据中的指示位置开始将数据发送到连接的 Socket
Socket.Receive:将数据从连接的 Socket 接收到接收缓冲区的特定位置
Socket.Bind :使 Socket 与一个本地终结点相关联
Socket.Listen:将 Socket 置于侦听状态
Socket.Accept:创建新的 Socket 以处理传入的连接请求
Socket.Close:强制 Socket 连接关闭
- Socket网络编程服务器端编程步骤
(1) 创建用于监听连接的Socket对象
(2) 用指定的端口号和服务器的ip建立一个EndPoint对象
(3) Bind()方法绑定EndPoint
(4) Listen()方法开始监听
(5) 有客户端连接,Accept()方法创建一个新的用于和客户端进行通信的socket实例
(6) 通信
(7) 通信结束关闭socket。
【
例6-2】
编写服务端程序,建立指定端口的连接,监听连接的客户端发送的信息。程序主界面如图6-11所示:
图6-11 服务端主界面图
新建windows窗体应用程序,添加控件并设置属性如表6-1所示:
表6-1 控件及属性设置表
控件 |
属性 |
值 |
Form1 |
Text |
Socket服务器 |
Form1 |
Size |
600,400 |
Lable1 |
Text |
服务器端口 |
TextBox1 |
Text |
5678 |
TextBox1 |
Name |
txtPort |
Button1 |
Text |
开始监听 |
Button1 |
Name |
btnStart |
TextBox2 |
Name |
txtLog |
TextBox2 |
Multiline |
true |
TextBox3 |
Name |
txtMsg |
TextBox3 |
Multiline |
true |
Button2 |
Text |
发送信息 |
Button2 |
Name |
btnSend |
编写窗口事件代码如下:
private void btnStart_Click(object sender, EventArgs e)
{
try
{
Socket SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Any;
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
SocketWatch.Bind(point);
ShowMsg("监听成功!"+":"+GetCurrentTime());
SocketWatch.Listen(10);
Thread Th = new Thread(Listen);
Th.IsBackground = true;
Th.Start(SocketWatch);
}
catch (Exception)
{
MessageBox.Show("连接失败!");
}
}
Socket socketSend;
void Listen(object obj)
{
Socket SocketWatch = obj as Socket;
while (true)
{
//等待客户端连接,并创建一个负责通讯的Socket
socketSend = SocketWatch.Accept();
ShowMsg(socketSend.RemoteEndPoint.ToString() + "---连接成功!"+":"+GetCurrentTime());
Thread ThRecive = new Thread(Recive);
ThRecive.IsBackground = true;
ThRecive.Start(socketSend);
}
}
//不断调用接收消息的方法
void Recive(object obj)
{
Socket SocketSend = obj as Socket;
while (true)
{
try
{
//创建一个数组储存客户端发过来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
//实际收到的有效字节数
int r = SocketSend.Receive(buffer);
string str = Encoding.UTF8.GetString(buffer, 0, r);
//将buffer转化成字符串形式
if (r == 0)
{
break;
}
ShowMsg( SocketSend.RemoteEndPoint.ToString() + "---" + str+":"+GetCurrentTime());
}
catch (Exception)
{
MessageBox.Show("连接失败!");
}
}
}
//文本框追加方法
void ShowMsg(string str)
{
this.txtLog.AppendText(str + "\r\n");
}
private void Form1_Load(object sender, EventArgs e)
{
//取消对线程间的错误检查
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnSend_Click(object sender, EventArgs e)
{
string str = this.txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
}
// 获取当前系统时间的方法
static DateTime GetCurrentTime()
{
DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
return currentTime;
}
提示:本例可与【
例6-3】客户端代码结合使用完成与客户端数据通信。
任务实现
新建windows窗体应用程序,程序主界面如图6-12所示:
图6-12 ATM监控服务端主界面图
添加控件并设置属性如表6-2所示:
表6-2 控件及属性设置表
控件 |
属性 |
值 |
Form1 |
Text |
ATM监控服务器 |
Form1 |
Size |
800,500 |
Lable1 |
Text |
服务器端口 |
TextBox1 |
Name |
txtPort |
TextBox1 |
Text |
9110 |
Button1 |
Text |
开始监控 |
Button1 |
Name |
btnStart |
Button2 |
Text |
退出 |
Button2 |
Name |
btnExit |
TextBox2 |
Name |
txtMsg |
TextBox2 |
Multiline |
true |
TextBox2 |
Size |
420,360 |
Label2 |
Text |
步行街 |
Label3,Label5,Label7 |
BackColor |
Silver |
Label3 |
Name |
lblWalkColor |
Button3 |
Name |
btnWalkOk |
Button3,Button5,Button7 |
Text |
出警 |
Button4 |
Name |
btnWalkEsc |
Button4,Button6,Button8 |
Text |
销警 |
Label4 |
Text |
胜利街 |
Label5 |
Name |
lblWinColor |
Label6 |
Text |
考棚街 |
Label7 |
Name |
lblKaoPColor |
编写窗口事件代码如下:
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
// 创建一个和客户端通信的套接字
Socket socketwatch = null;
private void btnStart_Click(object sender, EventArgs e)
{
try
{
socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取服务端本地IP地址
IPAddress address = IPAddress.Any;
IPEndPoint point = new IPEndPoint(address, Convert.ToInt32(txtPort.Text));
socketwatch.Bind(point);
msgAppend("监听成功!---"+GetCurrentTime()+"\r\n");
socketwatch.Listen(10);
Thread Th = new Thread(Listen);
Th.IsBackground = true;
Th.Start(socketwatch);
}
catch (Exception)
{
msgAppend("服务器连接不成功!---" + GetCurrentTime() + "\r\n");
}
}
Socket socketSend=null ,socketSend1 = null, socketSend2 = null, socketSend3 = null;
void Listen(object obj)
{
Socket SocketListen = obj as Socket;
while (true)
{
try
{
socketSend = SocketListen.Accept();
string ip = ((IPEndPoint)socketSend.RemoteEndPoint).Address.ToString();
if(ip.Equals("192.168.8.11"))
{
socketSend1 = socketSend;
}
else if(ip.Equals("192.168.8.12"))
{
socketSend2 = socketSend;
}
else if (ip.Equals("192.168.8.13"))
{
socketSend3 = socketSend;
}
msgAppend(ip + ": 连接成功!");
//创建线程调用Recive方法
if(socketSend1!=null)
{
Thread ThRecive1 = new Thread(Recive);
ThRecive1.IsBackground = true;
ThRecive1.Start(socketSend1);
}
if (socketSend2 != null)
{
Thread ThRecive2 = new Thread(Recive);
ThRecive2.IsBackground = true;
ThRecive2.Start(socketSend2);
}
if (socketSend3 != null)
{
Thread ThRecive3 = new Thread(Recive);
ThRecive3.IsBackground = true;
ThRecive3.Start(socketSend3);
}
} catch (Exception)
{
}
}
}
void Recive(object obj)
{
Socket SocketSend = obj as Socket;
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 2];
int r = SocketSend.Receive(buffer);
string str = Encoding.UTF8.GetString(buffer, 0, r);
if (r == 0)
{
break;
}
else if(str.Substring(0,2).Equals("A1"))
{
btnWalkOk.Enabled = true;
btnWalkEsc.Enabled = true;
lblWalkColor.BackColor = Color.Red;
str = "步行街报警";
}
else if (str.Substring(0, 2).Equals("C1"))
{
str = "步行街请求撤销警告";
}
else if (str.Substring(0, 2).Equals("A2"))
{
btnWinOk.Enabled = true;
btnWinEsc.Enabled = true;
lblWinColor.BackColor = Color.Red;
str = "胜利街报警";
}
else if (str.Substring(0, 2).Equals("C2"))
{
str = "胜利街请求撤销警告";
}
else if (str.Substring(0, 2).Equals("A3"))
{
btnKaoPengOk.Enabled = true;
btnKaoPengEsc.Enabled = true;
lblKaoPColor.BackColor = Color.Red;
str = "考棚街报警";
}
else if (str.Substring(0, 2).Equals("C3"))
{
str = "考棚街请求撤销警告";
}
msgAppend(str+"...---"+ GetCurrentTime());
}
catch (Exception)
{
}
}
}
void msgAppend(string msg)
{
txtMsg.AppendText(msg + "\r\n");
}
// 获取当前系统时间
static DateTime GetCurrentTime()
{
DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
return currentTime;
}
private void btnExit_Click(object sender, EventArgs e)
{
if(socketwatch!=null)
{
socketwatch.Close();
}
this.Close();
}
private void btnWalkOk_Click(object sender, EventArgs e)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("B1");
msgAppend("步行街出警中...---" + GetCurrentTime() );
socketSend1.Send(buffer);
lblWalkColor.BackColor = Color.Blue;
}
private void btnWalkEsc_Click(object sender, EventArgs e)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("C1");
msgAppend("步行街撤销警告...---" + GetCurrentTime());
socketSend1.Send(buffer);
lblWalkColor.BackColor = Color.Silver;
}
private void btnWinOk_Click(object sender, EventArgs e)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("B2");
socketSend2.Send(buffer);
msgAppend("胜利街出警中...---" + GetCurrentTime());
lblWinColor.BackColor = Color.Blue;
}
private void btnWinEsc_Click(object sender, EventArgs e)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("C2");
msgAppend("胜利街撤销警告...---" + GetCurrentTime());
socketSend2.Send(buffer);
lblWinColor.BackColor = Color.Silver;
}
private void btnKaoPengOk_Click(object sender, EventArgs e)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("B3");
socketSend3.Send(buffer);
msgAppend("考棚街出警中...---" + GetCurrentTime());
lblKaoPColor.BackColor = Color.Blue;
}
private void btnKaoPengEsc_Click(object sender, EventArgs e)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("C3");
msgAppend("考棚街撤销警告...---" + GetCurrentTime());
socketSend3.Send(buffer);
lblKaoPColor.BackColor = Color.Silver;
}
提示:
- 服务器端代码默认“步行街”、“胜利街”、“考棚街”客户端IP地址分别为“192.168.8.11”、“192.168.8.12”、“192.168.8.13”,如果实际IP地址不相符,需要修改代码中对应的IP地址。
- 项目设计思路为:服务器端“出警”分别向客户端发送“B1”、“B2”、“B3”,“销警”分别向客户端发送“C1”、“C2”、“C3”,客户端“报警”分别向服务器端发送“A1”、“A2”、“A3”,“销警”分别向服务器端发送“C1”、“C2”、“C3”。
- 如果客户端比较多,可使用Dictionary<string, Socket>集合类创建Socket实例。
任务小结
- Socket网络编程需要引用命名空间System.Net.Sockets、System.Net。
- 先运行服务器端程序进入监控,后运行客户端程序。
在Form_Load事件中设置Control.CheckForIllegalCrossThreadCalls = false; 取消对线程间的错误检查。
上一篇:C#应用实训|项目六 ATM机自动报警系统
下一篇:C#应用实训|任务2 客户端功能实现