• Socket网络编程--初级


    如果想开发一个基于TCP/IP协议的网络程序,应用程序之间则主要通过Socket交换数据

    .NET Socket支持四种编程模式

    1.居于阻塞模式的Socket编程

    2.”非阻塞“模式的Socket编程

    3.使用IAsyncResult的异步编程模式

    4.使用EAP的异步编程模式

    为什么要学Socket

    开始写代码 :

    Socket从信息的”发送“与”接收“角度,Socket分为两类:

    Server端Socket:它在指定的端口上监听,等待客户端的连接请求,并且向客户端发送接收数据

    Client端Socket:它尝试连接Server端的Socket,在连接成功之后,与Server端应用程序相互收发数据

    首先开发服务端的程序:

    准备:用于绑定的终结点IpEndPoint

    //准备:用于绑定的终结点
                IPAddress ipAddress = AddressHelper.GetLocalhostIPv4Address().First();
                int LocalPort = AddressHelper.GetOneAvaiablePortInLocalhost();
                IPEndPoint ipEnd = new IPEndPoint(ipAddress, LocalPort);

    1.创建Socket对象

    //1.创建Socket
                Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    2.绑定终结点

    //2. Socket绑定终结点
                    server.Bind(ipEnd);

    3.监听

    //3.监听
                    server.Listen(10);
                    Console.WriteLine("主机 {0} 正在监听端口 {1} ,等待客户端连接……", ipAddress, ipEnd.Port);

    4.响应连接请求:

    //4. 如果有连接 响应连接请求
                    Socket client = server.Accept();
    
                    IPEndPoint clientIpEnd = client.RemoteEndPoint as IPEndPoint;
                    Console.WriteLine("已接收客户端请求 客户端ip地址{0},端口号{1}", clientIpEnd.Address, clientIpEnd.Port);
                    string welcome = "欢迎使用本网络服务,请输入字符串 输入exit退出";
                    //将欢迎信息发送给客户端
                    data = Encoding.UTF8.GetBytes(welcome);
                    client.Send(data, data.Length, SocketFlags.None);

    5.服务端Socket接收数据,处理数据,在客户端要求断开连接的时候,关闭socket

     while (true)
                    {
                        //TODO 实现可以同时连接多个客户端的程序 实现两个客户端互相通信
                        //5.服务端Scoket开始接收客户端的数据,并将响应信息传回客户端
                        int recv = client.Receive(data);
                        string message = Encoding.UTF8.GetString(data, 0, recv);
                        if (message.Equals("exit"))
                        {
                            //关闭Socket
                            Console.WriteLine("客户端{0}已断开连接",clientIpEnd.Address);
                            client.Close();
                            break;
                        }
                        else
                        {
                            //将响应信息传给客户端
                            Console.WriteLine("客户端发来消息:{0}", message);
                            string sendMsg = string.Format("服务器已经收到您的消息:{0}", message);
                            client.Send(Encoding.UTF8.GetBytes(sendMsg));
                        }
    
                    }
                }

    2-5过程为了简化socket的操作,我用using(server){2-5的过程} 把2-5的代码给包起来了

    using (server)
                {   //2. Socket绑定终结点
                    //3.监听
                    //4. 如果有连接 响应连接请求
                     //5.服务端Scoket开始接收客户端的数据,并将响应信息传回客户端
                }    

    服务端就是这样子了

    下面是客户端Client

    1.创建Socket对象

    2.调用socket对象的Connect的方法创建连接

    3.发送数据

    整体代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading.Tasks;
    using MyNetworkLibrary;
    
    namespace MyClientApp
    {
        class Program
        {
            private const int BufferSize = 1024;
            static void Main(string[] args)
            {
                byte[] data = new byte[BufferSize];
                IPEndPoint ipEnd = AddressHelper.GetRemoteMachineIPEndPoint();
                //1.创建Socket对象
                Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //2.调用Connect创建连接
                try
                {
                    client.Connect(ipEnd.Address, ipEnd.Port);
                    Console.WriteLine("服务器端已连接");
                }
                catch (SocketException e)
                {
    
                    Console.WriteLine("无法连接远程主机{0},原因{1},NativeErrorCode{2},SocketErrorCode{3}", ipEnd.Address, e.Message, e.NativeErrorCode, e.SocketErrorCode);
                    Console.WriteLine("敲任意键退出");
                    Console.ReadKey();
                    return;
                }
                string recvData = "";
                int recv = client.Receive(data);
                recvData = Encoding.UTF8.GetString(data, 0, recv);
                Console.WriteLine(recvData);
    
                //发送数据
                string UserInput = "";
                while (true)
                {
                    UserInput = Console.ReadLine();
                    if (string.IsNullOrEmpty(UserInput))
                        continue;
                    byte[] SendBytes = Encoding.UTF8.GetBytes(UserInput);
                    client.Send(SendBytes);
                    if (UserInput == "exit")
                    {
                        client.Shutdown(SocketShutdown.Both);
                        client.Close();
                        Console.WriteLine("您选择断开与服务器的连接");
                        break;
                    }
                    recv = client.Receive(data);
                    recvData = Encoding.UTF8.GetString(data, 0, recv);
                    Console.WriteLine(recvData);
                }
                Console.WriteLine("敲任意键退出...");
                Console.ReadKey();
            }
        }
    }

    这里,我将服务端和客户端需要的一些数据封装到一MyNetworkLibrary类库中去,方便调用,和以后的扩展

    代码贴一下

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Net;
     4 using System.Net.Sockets;
     5 using System.Threading;
     6 
     7 namespace MyNetworkLibrary
     8 {
     9     public static class AddressHelper
    10     {
    11         /// <summary>
    12         /// 获取本地IPv4地址的集合
    13         /// </summary>
    14         /// <returns></returns>
    15         public static IPAddress[] GetLocalhostIPv4Address()
    16         {
    17             string LocalhostName = Dns.GetHostName();
    18             IPHostEntry host = Dns.GetHostEntry(LocalhostName);
    19             List<IPAddress> addresses = new List<IPAddress>();
    20             foreach (IPAddress ipAddress in host.AddressList)
    21             {
    22                 if(ipAddress.AddressFamily == AddressFamily.InterNetwork)
    23                     addresses.Add(ipAddress);
    24             }
    25             return addresses.ToArray();
    26         }
    27         /// <summary>
    28         /// 以交互的方式生成有效的远程主机访问终结点,适用于控制台
    29         /// </summary>
    30         /// <returns></returns>
    31         public static IPEndPoint GetRemoteMachineIPEndPoint()
    32         {
    33             IPEndPoint ipEnd = null;
    34             try
    35             {
    36                 Console.Write("请输入远程主机的ip地址:");
    37                 IPAddress ipAddress = IPAddress.Parse(Console.ReadLine());
    38                 Console.Write("请输入远程主机的端口号:");
    39                 int port = Convert.ToInt32(Console.ReadLine());
    40                 if (port >65535 || port < 1024)
    41                 {
    42                     throw new Exception("端口号为[1024,65535]之间整数");
    43                 }
    44                 ipEnd = new IPEndPoint(ipAddress,port);
    45 
    46             }
    47             catch (ArgumentNullException)
    48             {
    49                 Console.WriteLine("输入的数据有误!");
    50                 
    51             }
    52             catch (FormatException)
    53             {
    54                 Console.WriteLine("输入的数据有误!");
    55             }
    56             catch (Exception ex)
    57             {
    58                 Console.WriteLine(ex.Message);
    59             }
    60             return ipEnd;
    61         }
    62         /// <summary>
    63         /// 获取本机当前可用的端口号,此方法是线程安全的
    64         /// </summary>
    65         /// <returns></returns>
    66         public static int GetOneAvaiablePortInLocalhost()
    67         {
    68             Mutex mtx = new Mutex(false, "MyNetworkLibrary.AddressHelper.GetOneAvailablePort");
    69             try
    70             {
    71                 mtx.WaitOne();
    72                 IPEndPoint ep = new IPEndPoint(IPAddress.Any,0);
    73                 using (Socket tempSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp))
    74                 {
    75                     tempSocket.Bind(ep);
    76                     IPEndPoint ipEnd = tempSocket.LocalEndPoint as IPEndPoint;
    77                     return ipEnd.Port;
    78                 }
    79 
    80             }
    81             finally
    82             {
    83                 mtx.ReleaseMutex();
    84             }
    85         } 
    86     }
    87 }

    好啦 这样就写完一个简单的一对一的Socket网络程序了 

    看一下效果

  • 相关阅读:
    MyEclipse中选择一行的快捷键
    myeclipse选中一行的内容,快速移动复制到某一行。
    为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?
    webpack-dev-server
    webpack-clean-webpack-plugin
    --save-dev和--save的区别
    extract-text-webpack-plugin 的使用及安装
    this 指向详细解析(箭头函数)
    CSS三:CSS的三种引入方式
    Webpack中的css-loader 和style-loader
  • 原文地址:https://www.cnblogs.com/c-supreme/p/8629091.html
Copyright © 2020-2023  润新知