zoukankan      html  css  js  c++  java
  • TCP/IP协议学习(五) 基于C# Socket的C/S模型

      TCP/IP协议作为现代网络通讯的基石,内容包罗万象,直接去理解理论是比较困难的;然而通过实践先理解网络通讯的理解,在反过来理解学习TCP/IP协议栈就相对简单很多。C#通过提供的Socket API实现了对TCP/IP协议栈的封装,让实现C/S模型变得更加简单,对于入门TCP/IP协议学习十分有帮助。

       Socket通讯实现参考标准的流程如图所示,

    ·

      服务器工作:

      1.创建Socket套接字,绑定指定host,并监听。

        2.线程堵塞等待用户端请求,当客户端请求到达时建立连接。

      3.连接建立完成后,读取请求并处理,然后将处理结果返回给客户端。

      4. 服务器等待客户端关闭连接,连接关闭后,一次Socket通讯结束。

        客户端工作:

       1.创建Socket套接字, 建立连接,发送连接请求数据

        2. 请求成功后,等待服务器返回响应

        3.服务器回应成功后,处理数据,直到主动关闭连接。

      了解了上述Socket通讯的主要过程,在结合C#网络编程的特性,就可以实现如下C/S服务器。客户端的实现比较简单,主要分四个步骤:

      1.建立tcp连接(等同于socket 和 connect),处理连接失败状态

        2.对于建立成功的连接,发送数据,并等待服务器返回

        3.接收数据,输出到编辑框

        4.关闭连接

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            string s_ipaddress0 = textBox1.Text;
            string s_ipaddress1 = textBox2.Text;
            string s_ipaddress2 = textBox3.Text;
            string s_ipaddress3 = textBox4.Text;
            string s_port = textBox5.Text;
    
            //限定port的合法性
            bool isPort;
            int port;
            isPort = Int32.TryParse(s_port, out port);
            if (!(isPort && port >= 0 && port <= 65536))
            {
                OutToClient("Port is Invalid!");
                return;
            }
    
            //限定ip地址的合法性
            string host = s_ipaddress0 + "." + s_ipaddress1 + "." + s_ipaddress2 + "." + s_ipaddress3;
            if (!IsIpAdress(host))
            {
                OutToClient("IpAdress is invaild!");
                return;
            }
            IPAddress ip = IPAddress.Parse(host);
            IPEndPoint ipe = new IPEndPoint(ip, port); //Ip端口绑定 如192.168.1.48:80
    
            //发送框不能为空, 不然会导致GetBytes出错
            if (textBox6.Text == "")
            {
                OutToClient("Send Text is empty!");
                return;
            }
    
            OutToClient("Conneting...");
    
            int timeout = 1000;
    
            //tcpClient连接到指定端口,并处理超时
            TcpClient NetworkClient = TimeOutSocket.Connect(ipe, timeout);
            NetworkStream ntwStream = NetworkClient.GetStream();
            if (!ntwStream.CanWrite)
            {
                OutToClient("Data can not be write!");
                return;
            }
    
            //向绑定地址端口发送数据
             OutToClient("Client send:" + textBox6.Text);
            string sendStr = textBox6.Text;
            byte[] by_send = Encoding.ASCII.GetBytes(sendStr);
            ntwStream.Write(by_send, 0, by_send.Length);
    
            //等待服务器端返回数据
            string recvStr = "";
            byte[] recvBytes = new byte[4096];
            int bytes = ntwStream.Read(recvBytes, 0, recvBytes.Length);
    
            //将接收到数据转发输出到Client编辑框
            recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
            OutToClient(recvStr);
    
            //关闭连接, 一次发送完成
            ntwStream.Close();                                              
            NetworkClient.Close();
            OutToClient("Conneting Close!
    ");
        }
        catch (ArgumentNullException ii)
        {
            OutToClient("ArgumentNullException: "+ ii);
        }
        catch (SocketException ii)
        {
            OutToClient("Socket failed! ");
        }
        catch (Exception ii)
        {
            OutToClient("Conneting faild!" + ii);
        }
    }

      服务器内的代码涉及到的知识多一些

        1.通过按键1开辟监听线程,用于接收

        2.监听线程创建Socket套接字,绑定到指定端口并监听

        3.监听线程堵塞在等带连接建立

        4.连接建立后监听线程读取客户端数据并回送给客户端处理后数据,然后循环堵塞在连接建立

        5.通过按键2删除Socket套接字触发异常,结束线程

        按照上述的流程,程序如下:

    //新建线程 开始监听
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            isConnectExit = false;
            button1.Enabled = false;
            button2.Enabled = true;
    
            Thread Listen_thread = new Thread(ListenClientConnect);
            Listen_thread.IsBackground = true;
            Listen_thread.Start();
        }
        catch (Exception ii)
        {
            OutToServer("Connet faild!" + ii);
        }
    }
    //监听线程 主要处理数据接收发送
    private void ListenClientConnect(object obj)
    {
        string s_ipaddress0 = textBox1.Text;
        string s_ipaddress1 = textBox2.Text;
        string s_ipaddress2 = textBox3.Text;
        string s_ipaddress3 = textBox4.Text;
        string s_port = textBox5.Text;
    
        //限定port的合法性
        bool isPort;
        int port;
        isPort = Int32.TryParse(s_port, out port);
        if (!(isPort && port >= 0 && port <= 65536))
        {
            OutToServer("Port is Invalid!");
            return;
        }
    
        //限定ip地址的合法性
        string host = s_ipaddress0 + "." + s_ipaddress1 + "." + s_ipaddress2 + "." + s_ipaddress3;
        if (!IsIpAdress(host))
        {
            OutToServer("IpAdress is invaild!");
            return;
        }
    
        IPAddress ip = IPAddress.Parse(host);
        IPEndPoint ipe = new IPEndPoint(ip, port);
    
        //新建socket通讯 绑定指定IP+Port 并监听
        server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        server_socket.Bind(ipe);
        server_socket.Listen(10);
    
        OutToServer("wait for connect...");
        while (isConnectExit == false)
        {
            Socket CurrentSocket;
            try
            {
                //等待连接 完成三次握手
                CurrentSocket = server_socket.Accept();
                if(isConnectExit == true)
                {
                    CurrentSocket.Close();                     // 关闭Socket
                    server_socket.Close();
                    break;
                }
                OutToServer("Get a Connect!");
                ServerProcess(CurrentSocket);
            }
            catch
            {
                OutToServer("Connet exti!");
            }
        }
    }
    //断开连接
    private void button2_Click(object sender, EventArgs e)
    {
        isConnectExit = true;
        button2.Enabled = false;
        button1.Enabled = true;
        if (server_socket != null)
        {
            server_socket.Close();
        }
    }

    如此就完成了简单的C/S服务器功能。

    实际测试界面如下:

    具体源码参考:C/S架构客户端-服务器下载

    备注:本程序仅用于演示TCP socket通信流程,服务器端能够监听的IP地址只有本机IP或者127.x.x.1(环回地址), 端口不能为80(和本机http端口冲突)。

  • 相关阅读:
    CAP
    plugins for ST3 to frontend
    OAuth 2.0 详解
    Git SSH生成
    Android FrameWork 学习之Android 系统源码调试
    node.js安装步骤
    数据结构-- 队列 循环与顺序
    jsp之认识 servlet (基础、工作原理、容器请求处理)
    android 蓝牙开发---与蓝牙模块进行通讯 基于eclipse项目
    Android 仿微信调用第三方应用导航(百度,高德、腾讯)
  • 原文地址:https://www.cnblogs.com/zc110747/p/4905035.html
Copyright © 2011-2022 走看看