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网络程序了 

看一下效果

 

posted @ 2018-03-23 11:00  C_supreme  阅读(245)  评论(0编辑  收藏  举报