zoukankan      html  css  js  c++  java
  • 一个基于TCP/IP的服务器与客户端通讯的小项目(超详细版)

    1.目的:实现客户端向服务器发送数据

      原理:

    2.建立两个控制台应用,一个为服务器,用于接收数据。一个为客户端,用于发送数据。

      关键类与对应方法:

      1)类IPEndPoint:

      1.是抽象类EndPoint的实现类

      2.Socket对象的RemoteEndPoint、 LocalEndPoint都是这个类型

      3.属性Address: 使用IPv4表示的地址

      4.属性Port:使用int表示的端口

      2)类Socket:

      这个类即可以用于作服务器端的开发,又可以作客户端的开发

      构造方法:

      参数 AddressFamily:指定使用IPv4的地址InterNetwork

      参数SocketType:指定使用流式传输Stream

      参数ProtocolType:指定协议类型Tcp

      1.方法Bind()E 绑定IP与端口,这样就成为了服务器,可以监听指定IP的特定端口

      2.方法Listen(); 置于监听状态,参数是最大的挂起数

      3.方法Accept(): 接收客户端连接,返回Socket对象, 这个方法会阻塞当前线程,建议开启新线程执行些方法,结合尾递归,这样就可以接收多个客户端

      4.方法Receive(): 接收客户端发送过来的消息,以字节为单位进行操作,此方法会阻塞当前线程,建议开启新线程执行此方法,结合尾递归,就可以持续接收多条信息

      5. 方法Send(): 发送消息,以字节为单位

    3.具体实现

         其他内容不做过多解释了,备注做的超详细,应该只有笨笨的人才写这么多备注吧。。

      1.服务器

         主函数:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ServerTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                // 调用构造函数,使用Start方法
                ServerControl server = new ServerControl();
                server.Start();
    
                Console.ReadKey();
            }
        }
    }

         ServerControl类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ServerTest
    {
        public class ServerControl
        {
            // 声明变量(使用Socket需using System.Net.Sockets;)
            private Socket serverSocket;
    
            // 自定义有参构造方法(IP地址,流程传输方式,TCP协议)
            public ServerControl()
            {
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
    
            // 创建启动方法(IPEndPoint用于指定地址及端口初始化,需using System.Net;)
            public void Start()
            {
                // 服务器启动
                // 绑定IP地址(为任意IP)与端口(设置为12345)
                serverSocket.Bind(new IPEndPoint(IPAddress.Any,12345));
                serverSocket.Listen(10);
                Console.WriteLine("服务器启动成功");
    
                // 开启线程:目的实现服务器和客户端一对多连接
                Thread threadAccept = new Thread(Accept);
                threadAccept.IsBackground = true;
                threadAccept.Start();
            }
             // Accept方法测试:接收客户端连接
            private void Accept()
            {
                // 接收客户端方法,会挂起当前线程(.RemoteEndPoint表示远程地址)
                Socket client = serverSocket.Accept();
                IPEndPoint point = client.RemoteEndPoint as IPEndPoint;
                Console.WriteLine(point.Address + "[" + point.Port + "] 连接成功!");
    
                // 开启一个新线程线程,实现消息多次接收
                Thread threadReceive = new Thread(Receive);
                threadReceive.IsBackground = true;
                threadReceive.Start(client);
    
                // 尾递归
                Accept();
            }
    
            // Receive方法的使用测试
            // 接收客户端发送过来的消息,以字节为单位进行操作
            // 该方法会阻塞当前线程,所以适合开启新的线程使用该方法
            // Accept()中将Receive作为线程传递对象,所以要注意一点,使用线程传递对象只能是object类型的!!
            private void Receive(object obj)
            {
                // 将object类型强行转换成socket
                Socket client = obj as Socket;
    
                IPEndPoint point = client.RemoteEndPoint as IPEndPoint;
    
                // 此处的异常抛出主要针对客户端异常的问题
                // 比如,客户端关闭或者连接中断
                // 程序会停留在int msgLen = client.Receive(msg);这段代码,而导致无法继续往下走
                try
                {
                    byte[] msg = new byte[1024];
                    // 实际接收到字节数组长度,该方法会阻塞当前线程,即(client.Receive(msg)开始挂起)
                    // 同时,这里还是尾递归挂起处
                    int msgLen = client.Receive(msg);
                    // 将msg装换成字符串
                    Console.WriteLine(point.Address + "[" + point.Port + "]:" + Encoding.UTF8.GetString(msg, 0, msgLen));
                    // 此处实现服务器自动向客户端返回一条消息
                    // 因为Send发送信息是以字节为单位发送的
                    // 所以下面(Encoding.UTF8.GetString(msg,0,msgLen)+"   yes.boy")这一块是把这一部分均搞成string
                    // 后使用Encoding.UTF8.GetBytes统一转化成字节传递
                    // 这里呢,已经实现服务器向客户端发送消息了,客户端只需要receive一下,格式一转就可视化了
                    client.Send(Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(msg,0,msgLen)+"   yes.boy"));
                    // 尾递归实现多条消息的接收;和while同理。
                    Receive(client);
                }
                catch
                {
                    Console.WriteLine(point.Address + "[" + point.Port + "]积极断开");
                }
            }
        }
    }

    2.客户端:

       主函数:

    client.Connect("127.0.0.1",12345);
    修改IP可实现不同计算机之间的连接。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ClientTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                // 调用构造函数
                ClientControl client = new ClientControl();
                // 输入本机IP与端口号
                client.Connect("127.0.0.1",12345);
                // 提示操作方法
                Console.WriteLine("请输入发送至服务器的内容或者输入quit退出");
                // 输入内容
                string msg = Console.ReadLine();
                // 非退出情况下操作方式,使用while可以持续不断的接收用户输入
                while(msg != "quit")
                {
                    client.Send(msg);
                    msg = Console.ReadLine();
                }
    
                Console.ReadKey();
            }
        }
    }

       ClientControl类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ClientTest
    {
        public class ClientControl
        {
            // 声明变量
            private Socket clientSocket;
    
            // 自定义有参构造方法((IP地址,流程传输方式,TCP协议))
            public ClientControl()
            {
                clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            }
    
            // 创建通过IP与端口号连接的方法
            public void Connect(string ip,int port)
            {
                clientSocket.Connect(ip, port);
                Console.WriteLine("连接服务器成功");
    
                // 客户端接收服务器消息的线程
                Thread threadReceive = new Thread(Receive);
                threadReceive.IsBackground = true;
                threadReceive.Start();
            }
    
            // 用于测试服务器向客户端返回一条消息
            private void Receive()
            {
                while(true)
                {
                    try
                    {
                        // 用于接收服务器的回复信息
                        byte[] msg = new byte[1024];
                        int msgLen = clientSocket.Receive(msg);
                        Console.WriteLine("服务器:"+Encoding.UTF8.GetString(msg,0,msgLen));
                    }
                    // 异常处理方法
                    catch
                    {
                        Console.WriteLine("服务器积极拒绝!!");
                        // 退出while循环
                        break;
                    }
                }
            }
    
            // Send方法测试:即发送消息,以字节为单位
            public void Send(string msg)
            {
                // 将字符创传化为字节数组
                clientSocket.Send(Encoding.UTF8.GetBytes(msg));
            }
        }
    }

    4.实现

    本地连接:IP为127.0.0.1

    远程连接:因为我只有一台电脑,所以用腾讯云服务器作为我的服务器,我本地的PC作为客户端,实现连接。

    1.修改客户端主程序里面的IP为我的腾讯云IP

    2.使用远程桌面连接

    3.连接成功

  • 相关阅读:
    图像细节是高频,轮廓是低频
    Matlab实现西格玛(Sigma)平滑滤波
    Matlab实现细线化方法
    Matlab均匀性度量法实现图像二值化
    Matlab图像处理基础算法集锦(转载)
    Win7 下打开wifi共享的方法
    Day29 Matlab实现图像膨胀源代码
    时间类型和字符串类型之间的转换
    error: illegal character 'ufeff' 的解决方案
    无法卸载Sql Server 的解决办法
  • 原文地址:https://www.cnblogs.com/WeiMLing/p/11324133.html
Copyright © 2011-2022 走看看