学习C#高级编程之Socket编程

一个简单的服务器端和客户端程序

服务器端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _026_socket编程_TCP协议
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.创建socket
            Socket tcpServer = new Socket
                (AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            //对应属性分别是内网,流数据以及Tcp协议
            //2.绑定ip和端口号   172.16.1.102
            IPAddress ipaddress = new IPAddress(new byte[] {172,16,1,102});//获取ip地址
            EndPoint point = new IPEndPoint(ipaddress,7788);//IPEndPoint是对ip+端口做了一次封装的类
            tcpServer.Bind(point);//向操作系统申请一个可用的ip跟端口号 用来做通信
            //3.开始监听(等待客户端连接)
            tcpServer.Listen(100);//参数是最大连接数
            Console.WriteLine("开始监听");

            Socket clientSocket = tcpServer.Accept();//暂停当前线程,直到有一个客户端连接过来,之后进行下面的代码
            //使用返回的socket跟客户端做通信

            Console.WriteLine("一个客户端连接过来了");
            string message = "hello 欢迎你";
            byte[] data = Encoding.UTF8.GetBytes(message);//对字符串做编码,得到一个字符串的字节数组
            clientSocket.Send(data);

            Console.WriteLine("向客户端发送了一条数据");
            byte[] data2 = new byte[1024];//创建一个字节数组用来当做容器,去承接客户端发送过来的数据
            int length = clientSocket.Receive(data2);
            string message2 = Encoding.UTF8.GetString(data2, 0, length);//把字节数据转换成一个字符串
            Console.WriteLine("接收到了一个从客户端发送来的消息:" + message2);

            Console.ReadKey();
        }
    }
}

客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _001_socket编程_tcp协议_客户端
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.创建socket
            Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //2.发起建立连接的请求
            IPAddress ipaddress = IPAddress.Parse("172.16.1.102");//可以把一个字符串的IP地址转化成一个ipaddress的
            //对象
            EndPoint point = new IPEndPoint(ipaddress,7788); 
            tcpClient.Connect(point);//通过ip:端口号  定位一个要连接到的服务器端

            byte[] data = new byte[1024];
            int length = tcpClient.Receive(data);//这里传递一个byte数组,实际上这个data数组用来接收数据
            //length返回值表示接收了多少字节的数据
            string message =  Encoding.UTF8.GetString(data,0,length);//只把接收到的数据做一个转化
            Console.WriteLine(message);

            //向服务器端发送消息
            string message2 = Console.ReadLine();//读取用户的输入 把输入发送到服务器端
            tcpClient.Send(Encoding.UTF8.GetBytes(message2));//把字符串转化成字节数组,然后发送到服务器端


            Console.ReadKey();
        }
    }
}

服务器端结果

客户端结果

聊天室_socket_tcp服务器端

Client.cs用来和客户端做通信,处理客户端来的消息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace _027_聊天室_socket_tcp服务器端
{
    //用来和客户端做通信
    class Client
    {
        private Socket clientSocket;
        private Thread t;
        private byte[] data = new byte[1024];//数据容器

        public Client(Socket s)
        {
            clientSocket = s;
            //启动一个线程 处理客户端的数据接收
            Thread t = new Thread(ReceiveMessage);
            t.Start();
        }

        private void ReceiveMessage()
        {
            //一直接收客户端的数据
            while (true)
            {
                //在接收数据之前 判断一下socket链接是否断开
                if(clientSocket.Poll(10, SelectMode.SelectRead))
                {
                    clientSocket.Close();
                    break;//跳出循环 终止线程的执行
                }
                int length = clientSocket.Receive(data);
                string message = Encoding.UTF8.GetString(data, 0, length);
                //接收到数据的时候, 要把这个数据分发到客户端
                //广播这个消息
                Program.BroadcastMessage(message);
                Console.WriteLine("收到了消息:" + message);
            }
        }

        public void SendMessage(string message)
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            clientSocket.Send(data);
        }

        public bool Connected
        {
            get
            {
                return clientSocket.Connected;
            }
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _027_聊天室_socket_tcp服务器端
{
    class Program
    {
        static List<Client> clientList = new List<Client>();
        //广播消息
        public static void BroadcastMessage(string message)
        {
            var notConnectedList = new List<Client>();
            foreach (var client in clientList)
            {
                if(client.Connected)
                    client.SendMessage(message);
                else
                {
                    notConnectedList.Add(client);
                }
            }
            foreach(var temp in notConnectedList)
            {
                clientList.Remove(temp);
            }
        }
        static void Main(string[] args)
        {
            Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                ProtocolType.Tcp);
            tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.184.1"), 7788));
            tcpServer.Listen(100);
            Console.WriteLine("Server running...");

            while (true)
            {
                Socket clientSocket = tcpServer.Accept();
                Console.WriteLine("a client is connected!");
                Client client = new Client(clientSocket);//把与每个客户端通信的逻辑(收发消息)
                //放到client对象里面进行处理
                clientList.Add(client);
            }
        }
    }
}

客户端使用unity,界面如下:

核心代码:

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class ChatManager : MonoBehaviour {

    public string ipaddress = "192.168.184.1";
    public int port = 7788;
    public UIInput textInput;
    public UILabel chatLabel;

    private Socket clientSocket;
    private Thread t;
    private byte[] data = new byte[1024];//数据容器
    private string message = "";//消息容器
    // Use this for initialization
    void Start () {
        ConnectToServer();
	}
	
	// Update is called once per frame
	void Update () {
        if (message != null && message != "")
        {
            chatLabel.text += "\n" + message;
            message = "";//清空消息
        }
	}

    void ConnectToServer()
    {
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //跟服务器端建立连接
        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipaddress), port));

        //创建一个新的线程 用来接收消息
        t = new Thread(ReceiveMessage);
        t.Start();
    }
    
    //这个线程方法用来循环接收方法
    void ReceiveMessage()
    {
        while (true)
        {
            if (clientSocket.Connected == false)
                break;
            int length = clientSocket.Receive(data);
            message = Encoding.UTF8.GetString(data, 0, length);
            //chatLabel.text += "\n" + message;

        }
        
    }

    void SendMessage(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        clientSocket.Send(data);
    }

    public void OnSendButtonClick()
    {
        string value = textInput.value;
        SendMessage(value);
        textInput.value = "";
    }

    void OnDestroy()
    {
        clientSocket.Shutdown(SocketShutdown.Both);//关闭:既不接受,也不发送
        clientSocket.Close();//关闭链接
    }
}

结果展示如下:

UDP协议网络编程

服务器端

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 _028_socket编程_UDP协议_服务器端
{
    class Program
    {
        static Socket udpServer;
        static void Main(string[] args)
        {
            udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            udpServer.Bind(new IPEndPoint(IPAddress.Parse("172.16.1.102"), 7788));

            new Thread(ReceiveMessage) {IsBackground = true }.Start();

            //udpServer.Close();
            Console.ReadKey();
        }


        static void ReceiveMessage()
        {
            //接收数据
            while (true)
            {
                EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                byte[] data = new byte[1024];
                int length = udpServer.ReceiveFrom(data, ref remoteEndPoint);//这个方法会把数据的来源(ip:port)放到第二个参数上
                string message = Encoding.UTF8.GetString(data, 0, length);
                Console.WriteLine("从ip:" + (remoteEndPoint as IPEndPoint).Address.ToString() + ":" +
                    (remoteEndPoint as IPEndPoint).Port + "收到了数据:" + message);
            }
        }
    }
}

客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _002_socket编程_udp协议_客户端
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建socket
            Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //发送数据
            while (true)
            {
                EndPoint serverPoint = new IPEndPoint(IPAddress.Parse("172.16.1.102"), 7788);
                string message = Console.ReadLine();
                byte[] data = Encoding.UTF8.GetBytes(message);
                udpClient.SendTo(data, serverPoint);
            }
           
            Console.ReadKey();    
        }
    }
}

TCP与UDP的区别:

1.基于连接与无连接;

2.对系统资源的要求(TCP较多,UDP少);

3.UDP程序结构较简单;

4.流模式与数据报模式 ;

5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

TcpListener和TcpClient:两个封装类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _029_tcplistener
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.TcpListener对socket进行了封装,这个类里面自己会去创建socket对象
            TcpListener listener = new TcpListener(IPAddress.Parse("172.16.1.102"),7788);
            //2.开始进行监听
            listener.Start();//开始进行监听

            //3.等待客户端连接过来
            TcpClient client = listener.AcceptTcpClient();
            //4.取得客户端发送过来的数据
            NetworkStream stream = client.GetStream();//得到了一个网络流 从这个网络流可以取得客户端发送过来的数据
            while (true)
            {
                byte[] data = new byte[1024];//创建一个数据容器,用来承接数据
                int length = stream.Read(data, 0, 1024);//读取数据
                //0表示从数组的哪个索引开始存放数据
                //1024表示最大读取的字节数
                string message = Encoding.UTF8.GetString(data, 0, length);
                Console.WriteLine("收到了消息:" + message);

            }
            
           
            stream.Close();
            client.Close();
            listener.Stop();
            Console.ReadKey();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace tcpclient
{
    class Program
    {
        static void Main(string[] args)
        {
            //当我们创建tcpclient对象的时候,就会跟server去建立连接
            TcpClient client = new TcpClient("172.16.1.102",7788);
            NetworkStream stream = client.GetStream();
            //read用来读写数据,write用来写入数据就是发送数据
            while (true)
            {
                string message = Console.ReadLine();
                byte[] data = Encoding.UTF8.GetBytes(message);
                stream.Write(data, 0, data.Length);
            }
            

            stream.Close();
            client.Close();
            Console.ReadKey();
        }
    }
}

UdpClient

服务器端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _030_UdpClient
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建udpclient 绑定ip跟端口号
            UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse("172.16.1.102"),7788));

            //接收数据
            IPEndPoint point = new IPEndPoint(IPAddress.Any, 0);
            while (true)
            {
                byte[] data = udpClient.Receive(ref point);//确定point确定数据来自哪个IP的哪个端口号,返回的是一个字节数组,就是我们的数据
                string message = Encoding.UTF8.GetString(data);
                Console.WriteLine("收到了消息:" + message);
            }
          

            udpClient.Close();
            Console.ReadKey();
        }
    }
}

客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _004_udpclient
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建udpclient对象
            UdpClient client = new UdpClient();

            while (true)
            {
                string message = Console.ReadLine();
                byte[] data = Encoding.UTF8.GetBytes(message);
                client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("172.16.1.102"), 7788));
            }
            client.Close();
            Console.ReadKey();
        }
    }
}

结果

猜你喜欢

转载自blog.csdn.net/kouzhuanjing1849/article/details/81136672