Socket网络编程,TCP与UDP

Socket(套接字)网络编程流程简介 

TCP 协议:

使用TCP协议通讯需要具备以下几个条件:

    1.建立一个套接字(Socket)

    2.绑定服务器端的IP地址以及端口号

    3.利用Listen()方法开启监听

    4.利用Accept()方法尝试与客户端建立一个连接

    5.利用Connect()方法与服务器建立连接---客户端

    6.利用Send()方法互相发送消息

    7.利用Recive()方法互相接收消息

UDP协议

UDP协议是无连接模式通用,占用资源少,响应速度快,延时低,但是无法保证数据完整性,属于不可靠连接,但是其可靠性可以通过应用层的控制、对数据进行判断等方式来满足。

    1.建立一个套接字(socket)

    2.绑定服务器的端口号和IP

    3.通过SendTo()方法向主机发送消息,需要提供主机的端口号和IP

    4.通过ReciveFrom()方法接收指定主机发送的消息,需要提供主机IP和端口号

TCP协议与UDP协议的区别:

1.TCP协议需要建立连接; UDP连接无需建立连接,UDP结构比较简单。

2.TCP协议数据类型是以字节流的形式传输:SocketType.Stream;

    UDP协议数据类型以数据报的形式传输:SocketType.Dgram。

3.TCP保证数据的正确性、数据顺序等,具有可靠性,但是耗费资源大

   UDP可能会丢包、不保证数据顺序、不具有可靠性,耗费资源小、效率高

TCP服务端简单代码:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace Server
{
    public class Program
    {
        private static Func<string, string> write;
        public static Socket SocketServer { get; set; }
        public static List<Client> clients { get; set; }
        public static List<Client> notConnectedList { get; set; }
        static void Main(string[] args)
        {
            write = WriteMessage;
            write.BeginInvoke("写入", WriteEnd, write);

            clients = new List<Client>();
            notConnectedList = new List<Client>();

            SocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SocketServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.199.128"), 8888));
            SocketServer.Listen(100);
            Console.WriteLine("服务器启动成功。");
            while (true)
            {
                Socket clientSocket = SocketServer.Accept();

                Client client = new Client(clientSocket);        //把与每个客户端进行通信的逻辑放在Client类中进行处理
                clients.Add(client);
                Console.WriteLine("客户端连接成功,客户端数量:" + clients.Count);
            }
        }

        public static void BroadMassage(Client self, string mesage)
        {
            foreach (var client in clients)
            {
                if (client != self)
                    if (client.IsConnected)
                    {
                        client.SendMessage(mesage);
                    }
                    else
                    {
                        notConnectedList.Add(client);
                    }
            }
            ClineClient();
        }
        public static void BroadMassage(string mesage)
        {
            foreach (var client in clients)
            {
                if (client.IsConnected)
                {
                    client.SendMessage(mesage);
                }
                else
                {
                    notConnectedList.Add(client);
                }
            }
            ClineClient();
        }
        public static void ClineClient()
        {
            foreach (var item in notConnectedList)
            {
                if (clients.Contains(item))
                    clients.Remove(item);
                Console.WriteLine("客户端断开连接,客户端数量:" + clients.Count);
            }
            notConnectedList.Clear();
        }
        /// <summary>
        /// 服务器写入
        /// </summary>
        /// <param name="temp"></param>
        /// <returns></returns>
        public static string WriteMessage(string temp)
        {
            string message = Console.ReadLine();
            write.BeginInvoke("写入", WriteEnd, write);
            return message;
        }
        public static void WriteEnd(System.IAsyncResult result)
        {
            Func<string, string> func = (System.Func<string, string>)result.AsyncState;
            string message = func.EndInvoke(result);
            Console.WriteLine("写好的消息:" + message);
            Program.BroadMassage(message);
        }
    }
}
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Server
{
    /// <summary>
    /// 用来和服务端做通信
    /// </summary>
    public class Client
    {
        public bool IsConnected { get { return clientSocket.Connected; } }
       
        private Socket clientSocket;
        private Thread thread;
        private byte[] data = new byte[1024];
        public Client(Socket client)
        {
            clientSocket = client;
            thread = new Thread(MyResaveMessage);
            thread.IsBackground = true;
            thread.Start();
           
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message"></param>
        public void SendMessage(string message)
        {
            try
            {
                byte[] tempData = new byte[1024];
                tempData = Encoding.UTF8.GetBytes(message);
                clientSocket.Send(tempData);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        /// <summary>
        /// 接收消息
        /// </summary>
        public void MyResaveMessage()
        {
            while (true)
            {
                //在接受数据之前,判断连接是否断开
                if (clientSocket.Poll(100, SelectMode.SelectRead))
                {
                    clientSocket.Close();
                    break;
                }
                int lenth = clientSocket.Receive(data);
                string massage = Encoding.UTF8.GetString(data, 0, lenth);
                //接收到数据的时候,将数据发送到所有客户端
                Program.BroadMassage(this, massage);
            }

        }
    
    }
}

TCP协议客户端的简单代码

其中UIControl是用来写发送消息逻辑的,可以删除写自己的逻辑

using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// socket客户端
/// </summary>
public class SocaketClientTCP : MonoBehaviour
{
    public static Action<string> resiveMessage;
    public string IP = "192.168.199.128";
    public short port = 8888;

    Thread task1;
    private Socket socketClient;
    public void StartConnectingToTheServer()
    {
        //通过UI控制类委托来监听是否需要发送消息,可以写入自己的发送逻辑
        UIControl.scendMessage += MySendMessage;
        socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //以下代码可以进行简化
        IPAddress iPAddress = IPAddress.Parse(IP);
        EndPoint endPoint = new IPEndPoint(iPAddress, port);
        socketClient.Connect(endPoint);
        //传递一个需要线程去执行的方法,设置后台线程,在主线程关闭后,后台线程自动关闭
        task1 = new Thread(MyResaveMessage) {IsBackground=true};
        task1.Start();

    }
    /// <summary>
    /// 发送消息
    /// </summary>
    public void MySendMessage(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        try { socketClient.Send(data); }
        catch (Exception e) { Debug.Log("消息发送失败" + e); }
    }
    /// <summary>
    /// 接收消息
    /// </summary>
    public void MyResaveMessage()
    {
        byte[] data = new byte[1024];
        while (true)
        {
            // 通过这种方式判断是否断开连接比较可靠: socketClient.Poll(100, SelectMode.SelectRead);
            //判断当前连接是否断开
            if (!socketClient.Connected)
                break;
            int lenth = socketClient.Receive(data);
            string massage = Encoding.UTF8.GetString(data, 0, lenth);
            //将接收到的信息通过委托发送出去
            resiveMessage?.Invoke(massage);
        }
    }
    private void Start()
    {
        StartConnectingToTheServer();
    }
    private void OnDestroy()
    {
        task1.Abort();
        socketClient.Shutdown(SocketShutdown.Both);
        socketClient.Close();
    }
}

UDP协议接收消息的简单代码:由于UDP没有服务端和客户端的具体区分,所以写成两个部分来表示数据的发送和接收

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace ServerUDP
{
    class Program
    {
        public static string IP = "192.168.199.128";
        public static int Port = 8888;

        private static Socket socketServerUDP;
        static void Main(string[] args)
        {
            //1.创建Socket
            socketServerUDP = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //2.绑定IP和端口号
            socketServerUDP.Bind(new IPEndPoint(IPAddress.Parse(IP), Port));
            //3.通过线程接收数据接收数据
            new Thread(ReceiveMessage) { IsBackground = true }.Start();
            //4.发送数据需要直到目标位置的IP和端口号
            //与客户端发送消息一样,绑定目标位置的端口号和IP即可发送
        }
        /// <summary>
        /// 接收数据
        /// </summary>
        static void ReceiveMessage()
        {
            while (true)
            {
                byte[] data = new byte[1024];
                EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                int length = socketServerUDP.ReceiveFrom(data, ref remoteEndPoint);
                string message = Encoding.UTF8.GetString(data, 0, length);

                Console.WriteLine(message + "收到来自:  \nIP:"
                    + (remoteEndPoint as IPEndPoint).Address.ToString()
                    + "\nPort:" + (remoteEndPoint as IPEndPoint).Port.ToString()
                    + "的消息:" + message);
            }
        }
    }
}

UDP协议消息发送简单代码

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

public class SocketClientUDP : MonoBehaviour
{
    public string IP = "192.168.199.128";
    public int Port = 8888;

    private  Socket socketClientUDP;
    private EndPoint endPoint;
    // Start is called before the first frame update
    void Start()
    {
        //创建Socket
        socketClientUDP = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        //创建一个服务器的目标位置方便之后使用
        endPoint = new IPEndPoint(IPAddress.Parse(IP), Port);
        //启动线程接收数据
        new Thread(ReciveMessage) { IsBackground = true }.Start(); 
        
        UIControl.scendMessage += SendMessageToServer;
    }
    /// <summary>
    /// 发送数据
    /// </summary>
    public void SendMessageToServer(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        socketClientUDP.SendTo(data, endPoint);
    }
    /// <summary>
    /// 接收数据
    /// </summary>
    public void ReciveMessage()
    {
        while (true)
        {
            byte[] data = new byte[1024];
            EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
            //程序运行到ReceiveFrom后会进行等待,直到有消息发送过来才会执行下边的代码
            int length = socketClientUDP.ReceiveFrom(data, ref remoteEndPoint);
            string message = Encoding.UTF8.GetString(data, 0, length);
            Debug.Log("接收到数据:" + message);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值