C# Socket通信实例:从基础到实战


引言

Socket(套接字)是网络编程的基础,它提供了不同主机间进程通信的端点。在C#中,System.Net.Sockets命名空间提供了强大的Socket编程支持。本文将通过实际代码示例,详细介绍如何在C#中实现Socket通信,包括TCP和UDP两种协议的具体实现。

一、Socket编程基础

1.1 Socket基本概念

  • Socket:通信的端点,包含IP地址和端口号
  • TCP Socket:面向连接的可靠通信
  • UDP Socket:无连接的快速通信
  • 常见操作:Bind(绑定)、Listen(监听)、Accept(接受连接)、Connect(连接)、Send(发送)、Receive(接收)

1.2 核心类介绍

  • Socket:基础套接字类
  • TcpListener/TcpClient:TCP协议封装
  • UdpClient:UDP协议封装
  • IPEndPoint:表示网络端点(IP+端口)

二、TCP Socket通信实例

2.1 TCP服务器实现

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

public class TcpSocketServer
{
    private const int Port = 8888;
    private const int BufferSize = 1024;

    public static void Start()
    {
        // 创建服务器Socket
        Socket serverSocket = new Socket(AddressFamily.InterNetwork, 
                                      SocketType.Stream, 
                                      ProtocolType.Tcp);

        try
        {
            // 绑定IP和端口
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, Port);
            serverSocket.Bind(endPoint);

            // 开始监听,设置最大连接数
            serverSocket.Listen(10);
            Console.WriteLine($"服务器已启动,监听端口:{Port}");

            while (true)
            {
                Console.WriteLine("等待客户端连接...");

                // 接受客户端连接
                Socket clientSocket = serverSocket.Accept();
                Console.WriteLine($"客户端已连接:{clientSocket.RemoteEndPoint}");

                // 处理客户端请求
                HandleClient(clientSocket);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"服务器异常:{ex.Message}");
        }
        finally
        {
            serverSocket.Close();
        }
    }

    private static void HandleClient(Socket clientSocket)
    {
        byte[] buffer = new byte[BufferSize];

        try
        {
            // 接收客户端消息
            int received = clientSocket.Receive(buffer);
            string message = Encoding.UTF8.GetString(buffer, 0, received);
            Console.WriteLine($"收到消息:{message}");

            // 发送响应
            string response = $"服务器已收到你的消息:[{message}]";
            byte[] responseData = Encoding.UTF8.GetBytes(response);
            clientSocket.Send(responseData);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"处理客户端异常:{ex.Message}");
        }
        finally
        {
            // 关闭连接
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
            Console.WriteLine("客户端连接已关闭");
        }
    }
}

2.2 TCP客户端实现

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

public class TcpSocketClient
{
    private const string ServerIP = "127.0.0.1";
    private const int Port = 8888;
    private const int BufferSize = 1024;

    public static void Connect(string message)
    {
        Socket clientSocket = new Socket(AddressFamily.InterNetwork, 
                                      SocketType.Stream, 
                                      ProtocolType.Tcp);

        try
        {
            // 连接服务器
            clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ServerIP), Port));
            Console.WriteLine("已连接到服务器");

            // 发送消息
            byte[] sendData = Encoding.UTF8.GetBytes(message);
            clientSocket.Send(sendData);
            Console.WriteLine($"已发送消息:{message}");

            // 接收响应
            byte[] buffer = new byte[BufferSize];
            int received = clientSocket.Receive(buffer);
            string response = Encoding.UTF8.GetString(buffer, 0, received);
            Console.WriteLine($"服务器响应:{response}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"客户端异常:{ex.Message}");
        }
        finally
        {
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
        }
    }
}

三、UDP Socket通信实例

3.1 UDP服务器实现

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

public class UdpSocketServer
{
    private const int Port = 9999;
    private const int BufferSize = 1024;

    public static void Start()
    {
        // 创建UDP Socket
        Socket serverSocket = new Socket(AddressFamily.InterNetwork, 
                                      SocketType.Dgram, 
                                      ProtocolType.Udp);

        try
        {
            // 绑定端口
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, Port);
            serverSocket.Bind(endPoint);
            Console.WriteLine($"UDP服务器已启动,监听端口:{Port}");

            // 接收缓冲区
            byte[] buffer = new byte[BufferSize];
            EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);

            while (true)
            {
                Console.WriteLine("等待接收数据...");

                // 接收数据
                int received = serverSocket.ReceiveFrom(buffer, ref clientEP);
                string message = Encoding.UTF8.GetString(buffer, 0, received);
                Console.WriteLine($"收到来自 {clientEP} 的消息:{message}");

                // 发送响应
                string response = $"UDP服务器已收到:[{message}]";
                byte[] responseData = Encoding.UTF8.GetBytes(response);
                serverSocket.SendTo(responseData, clientEP);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"UDP服务器异常:{ex.Message}");
        }
        finally
        {
            serverSocket.Close();
        }
    }
}

3.2 UDP客户端实现

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

public class UdpSocketClient
{
    private const string ServerIP = "127.0.0.1";
    private const int Port = 9999;
    private const int BufferSize = 1024;

    public static void SendMessage(string message)
    {
        Socket clientSocket = new Socket(AddressFamily.InterNetwork, 
                                      SocketType.Dgram, 
                                      ProtocolType.Udp);

        try
        {
            // 服务器端点
            IPEndPoint serverEP = new IPEndPoint(IPAddress.Parse(ServerIP), Port);

            // 发送消息
            byte[] sendData = Encoding.UTF8.GetBytes(message);
            clientSocket.SendTo(sendData, serverEP);
            Console.WriteLine($"已发送UDP消息:{message}");

            // 接收响应
            byte[] buffer = new byte[BufferSize];
            EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
            int received = clientSocket.ReceiveFrom(buffer, ref remoteEP);
            string response = Encoding.UTF8.GetString(buffer, 0, received);
            Console.WriteLine($"服务器响应:{response}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"UDP客户端异常:{ex.Message}");
        }
        finally
        {
            clientSocket.Close();
        }
    }
}

四、Socket通信进阶技巧

4.1 异步Socket通信

使用异步方法提高服务器并发能力:

// 异步TCP服务器示例
public class AsyncTcpServer
{
    private const int Port = 8888;
    private static Socket serverSocket;

    public static void Start()
    {
        serverSocket = new Socket(AddressFamily.InterNetwork, 
                                SocketType.Stream, 
                                ProtocolType.Tcp);
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, Port));
        serverSocket.Listen(100);
        Console.WriteLine("异步服务器已启动");

        // 开始异步接受连接
        serverSocket.BeginAccept(AcceptCallback, null);
    }

    private static void AcceptCallback(IAsyncResult ar)
    {
        Socket clientSocket = serverSocket.EndAccept(ar);
        Console.WriteLine($"客户端连接:{clientSocket.RemoteEndPoint}");

        // 开始接收数据
        StateObject state = new StateObject();
        state.WorkSocket = clientSocket;
        clientSocket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, 
                                ReceiveCallback, state);

        // 继续接受其他连接
        serverSocket.BeginAccept(AcceptCallback, null);
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {
        StateObject state = (StateObject)ar.AsyncState;
        Socket clientSocket = state.WorkSocket;

        int bytesRead = clientSocket.EndReceive(ar);
        if (bytesRead > 0)
        {
            string message = Encoding.UTF8.GetString(state.Buffer, 0, bytesRead);
            Console.WriteLine($"收到消息:{message}");

            // 发送响应
            string response = $"异步响应:{message}";
            byte[] responseData = Encoding.UTF8.GetBytes(response);
            clientSocket.BeginSend(responseData, 0, responseData.Length, 0,
                                 SendCallback, clientSocket);
        }
    }

    private static void SendCallback(IAsyncResult ar)
    {
        Socket clientSocket = (Socket)ar.AsyncState;
        int bytesSent = clientSocket.EndSend(ar);
        Console.WriteLine($"已发送 {bytesSent} 字节");

        // 继续接收数据
        StateObject state = new StateObject();
        state.WorkSocket = clientSocket;
        clientSocket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, 
                                ReceiveCallback, state);
    }
}

// 状态对象类
public class StateObject
{
    public const int BufferSize = 1024;
    public byte[] Buffer = new byte[BufferSize];
    public Socket WorkSocket = null;
}

4.2 Socket异常处理

// 增强的Socket异常处理
try
{
    // Socket操作代码
}
catch (SocketException se)
{
    switch (se.SocketErrorCode)
    {
        case SocketError.ConnectionReset:
            Console.WriteLine("连接被重置");
            break;
        case SocketError.TimedOut:
            Console.WriteLine("操作超时");
            break;
        case SocketError.HostNotFound:
            Console.WriteLine("主机未找到");
            break;
        default:
            Console.WriteLine($"Socket异常:{se.Message}");
            break;
    }
}
catch (ObjectDisposedException ode)
{
    Console.WriteLine($"Socket已被释放:{ode.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"其他异常:{ex.Message}");
}

五、Socket通信最佳实践

  1. 资源管理
  • 使用using语句或确保Close()/Dispose()被调用
  • 正确使用Shutdown()方法
  1. 性能优化
  • 使用异步方法提高并发能力
  • 合理设置缓冲区大小
  • 重用Socket对象(如Socket池)
  1. 安全性
  • 使用SSL/TLS加密通信
  • 验证客户端身份
  • 防范DDoS攻击
  1. 错误处理
  • 处理所有可能的Socket异常
  • 实现重试机制
  • 添加超时设置
// 设置Socket超时示例
socket.ReceiveTimeout = 5000; // 5秒接收超时
socket.SendTimeout = 5000;    // 5秒发送超时

六、实际应用场景

6.1 实现简单聊天程序

// 聊天服务器
public class ChatServer
{
    private static List<Socket> clientSockets = new List<Socket>();

    public static void BroadcastMessage(string message, Socket sender)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);

        foreach (Socket client in clientSockets)
        {
            if (client != sender && client.Connected)
            {
                client.Send(data);
            }
        }
    }

    // 在AcceptCallback中添加新客户端到列表
    private static void AcceptCallback(IAsyncResult ar)
    {
        Socket clientSocket = serverSocket.EndAccept(ar);
        clientSockets.Add(clientSocket);
        // ...其余处理逻辑
    }
}

6.2 文件传输实现

// 文件发送端
public static void SendFile(Socket socket, string filePath)
{
    byte[] fileNameData = Encoding.UTF8.GetBytes(Path.GetFileName(filePath));
    socket.Send(BitConverter.GetBytes(fileNameData.Length));
    socket.Send(fileNameData);

    byte[] fileData = File.ReadAllBytes(filePath);
    socket.Send(BitConverter.GetBytes(fileData.Length));
    socket.Send(fileData);
}

// 文件接收端
public static void ReceiveFile(Socket socket, string saveDirectory)
{
    byte[] lengthBuffer = new byte[4];
    socket.Receive(lengthBuffer);
    int fileNameLength = BitConverter.ToInt32(lengthBuffer, 0);

    byte[] fileNameData = new byte[fileNameLength];
    socket.Receive(fileNameData);
    string fileName = Encoding.UTF8.GetString(fileNameData);

    socket.Receive(lengthBuffer);
    int fileLength = BitConverter.ToInt32(lengthBuffer, 0);

    byte[] fileData = new byte[fileLength];
    int received = 0;
    while (received < fileLength)
    {
        received += socket.Receive(fileData, received, fileLength - received, SocketFlags.None);
    }

    File.WriteAllBytes(Path.Combine(saveDirectory, fileName), fileData);
}

结论

通过本文的实例和讲解,我们全面了解了C#中Socket通信的实现方法。关键要点包括:

  1. TCP和UDP Socket的基本实现原理
  2. 同步和异步Socket编程模式
  3. 实际应用场景的实现技巧
  4. Socket编程的最佳实践和安全考虑

Socket编程是网络通信的基础,掌握这些技术可以帮助开发者构建各种网络应用,从简单的客户端/服务器程序到复杂的分布式系统。在实际开发中,应根据具体需求选择合适的通信协议和编程模式,并始终注意资源管理、性能优化和安全性问题。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注