辜渝傧

13037102709

027-87870986

教学实训

您当前的位置:首页 > 教学资源 > 实训方案 >

C#应用实训|任务1 服务器端功能实现

发布者:唯众    布时间:2020-12-21 13:41:49    点击量:

任务描述

       服务器端创建连接后,要实现客户端的信息监控,当客户端发送“报警”信息后,服务器端接收到信息要进行相应的“出警”处理,当客户端请求“撤消报警”后,服务器端接收到信息后要进行相应的“撤消警告”处理。

知识引入

  1. 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编程提供支持类。
  1. IPAddress 类
功能:提供主机的IP地址及相关信息。
  1. IPHostEntry类
功能:提供主机的IP地址、主机名及别名。
主要属性:
AddressList:返回IPAddress[ ],获取或设置与主机关联的IP地址列表。
HostName:返回string[ ],获取或设置主机的DNS名称。
  1. IPEndPoint类
功能:将网络端点表示为IP地址和端口号。通过IP地址和端口号的组合,构造主机的连接点。
主要属性:
Address:获取或设置终结点IP地址。
AddressFamily:获取网络协议(IP)地址族。AddressFamily.InterNetwork表示此IP为IPv4,
AddressFamily.InterNetworkV6表示此地址为IPv6类型。
Port:获取或设置终结点的端口号。
  1. Dns 类
功能:提供简单的域名解析功能。
主要属性:
  • :获取本地计算机的主机名。
  • :返回指定主机的Internet协议(IP)地址。
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);
        }
    }
}
  1. 端口
       在网络连接中,端口分为物理端口和逻辑端口,物理端口指计算机硬件的I/O端口,逻辑端口指逻辑意义上用于区分服务的端口,如TCP/IP协议中的服务端口,端口号的范围从0到65535。每一个网络连接都需要一个端口号,一般来说,每个端口都对应着一种应用程序。要建立客户机与服务器之间的连接通信,必须选择一个端口进行连接,端口号0-1023是标准的Internet协议保留端口,用户创建程序自定义端口号范围一般为8000-16000。
  1. 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 连接关闭
  1. 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;
        }
提示
  1. 服务器端代码默认“步行街”、“胜利街”、“考棚街”客户端IP地址分别为“192.168.8.11”、“192.168.8.12”、“192.168.8.13”,如果实际IP地址不相符,需要修改代码中对应的IP地址。
  2. 项目设计思路为:服务器端“出警”分别向客户端发送“B1”、“B2”、“B3”,“销警”分别向客户端发送“C1”、“C2”、“C3”,客户端“报警”分别向服务器端发送“A1”、“A2”、“A3”,“销警”分别向服务器端发送“C1”、“C2”、“C3”。
  3. 如果客户端比较多,可使用Dictionary<string, Socket>集合类创建Socket实例。

任务小结

  1. Socket网络编程需要引用命名空间System.Net.Sockets、System.Net。
  2. 先运行服务器端程序进入监控,后运行客户端程序。
在Form_Load事件中设置Control.CheckForIllegalCrossThreadCalls = false; 取消对线程间的错误检查。


上一篇:C#应用实训|项目六 ATM机自动报警系统

下一篇:C#应用实训|任务2 客户端功能实现