C# - 套接字:端口转发

C# - Sockets: Port Forwarding

我在网络程序中工作,但是当我测试代码时,我发现我的朋友(他们不在我的本地网络中)无法连接到服务器。现在我发现端口转发可能是问题所在,但我不知道如何更改我的代码,让我的朋友可以连接(当端口转发时,问题在于如何在我的代码中实现端口转发)。 这是我的 Classes: 服务器 class:

    static Socket listenerSocket;
    static List<ClientData> clients;
    static List<ClientName> clientNames;
    static List<ClientName> clientReady;
    private int port;

    public Server(int port)
    {
        InitializeComponent();
        this.port = port;
    }
    private void Server_Load(object sender, EventArgs e)
    {
        Start();
    }

    private void Start()
    {
        consoleList.Items.Add("Starting Server on " + Packet.GetIP4Address() + ":" + port);

        listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clients = new List<ClientData>();
        clientNames = new List<ClientName>();
        clientReady = new List<ClientName>();

        IPEndPoint point = new IPEndPoint(IPAddress.Parse(Packet.GetIP4Address()), port);
        try
        {
            listenerSocket.Bind(point);
        }
        catch (Exception)
        {
            MessageBox.Show("Port ist schon benutzt!");
            Close();
        }

        Thread listenThread = new Thread(ListenThread);
        listenThread.Start();
    }

    static void ListenThread()
    {
        for (;;)
        {
            listenerSocket.Listen(0);
            ClientData data = new ClientData(listenerSocket.Accept());
            clients.Add(data);
        }
    }

    public static void ResetReadyClientList()
    {
        ResetReadyClientList_Server();
    }

    private static void ResetReadyClientList_Server()
    {
        clientReady.Clear();
    }

    public static List<ClientName> GetReadyClientList()
    {
        return clientReady;
    }

    public static List<ClientName> GetClientList()
    {
        return clientNames;
    }

    public static void Data_IN(object cSocket)
    {
        Socket clientScoket = (Socket)cSocket;

        byte[] buffer;
        int readBytes;

        for (;;)
        {
            buffer = new byte[clientScoket.SendBufferSize];

            readBytes = clientScoket.Receive(buffer);

            if(readBytes > 0)
            {
                Packet packet = new Packet(buffer);
                DataManager(packet);
            }
        }
    }

    static List<String> packetsReceived = new List<string>();
    static List<String> clientsHasDownloaded = new List<string>();

    static String path;

    public static void DataManager(Packet p)
    {
        switch (p.packetType)
        {
            case PacketType.OutWindow:
                String name = GetName(p.senderID);
                MessageBox.Show(name + " hat aus dem Fenster geklickt!");
                break;
            case PacketType.RegisterName:
                ClientName cName = new ClientName(p.senderID, p.gData[0]);

                clientNames.Add(cName);
                break;
            case PacketType.Answer:
                String senderName = GetName(p.senderID);
                String answer = p.gData[0];
                MessageBox.Show("Spieler " + senderName + " hat " + answer + " getippt!");
                ClientName c = new ClientName(p.senderID, GetName(p.senderID));
                if (clientReady.Contains(c)) clientReady.Remove(c);
                clientReady.Add(c);
                break;
            case PacketType.HasDownloaded:
                clientsHasDownloaded.Add(p.senderID);
                if (clientsHasDownloaded.Count == clients.Count)
                {
                    SoundHostForm form = new SoundHostForm();
                    form.ShowDialog();
                    path = p.gData[0];
                }
                break;
        }
    }

    static ClientData GetClientData(String id)
    {
        foreach (ClientData c in clients)
        {
            if(c.id == id)
            {
                return c;
            }
        }
        return null;
    }

    public static void SendFileToAll(String path)
    {
        Thread t = new Thread(() => SendFile(path));
        t.Start();
    }

    private static void SendFile(String path)
    {
        clientsHasDownloaded.Clear();

        Uri downloadLink = FileTransfer.UploadFile(path);

        Packet p = new Packet(PacketType.CanDownload, "server");
        p.gData.Add(downloadLink.ToString());

        foreach (ClientData data in clients)
        {
            data.clientSocket.Send(p.ToBytes());
        }
    }

    public static void SendPacketToAll(Packet p)
    {
        foreach(ClientData data in clients)
        {
            data.clientSocket.Send(p.ToBytes());
        }
    }

    static String GetName(String id)
    {
        foreach (ClientName c in clientNames)
        {
            if (c.id == id)
            {
                return c.name;
            }
        }
        return null;
    }

}
class ClientData
{
    public Socket clientSocket;
    public Thread clientThread;
    public String id;

    public ClientData()
    {
        id = Guid.NewGuid().ToString();
        clientThread = new Thread(Server.Data_IN);
        clientThread.Start(clientSocket);
        SendRegisterationPacket();
    }

    public ClientData(Socket clientSocket)
    {
        this.clientSocket = clientSocket;
        id = Guid.NewGuid().ToString();
        clientThread = new Thread(Server.Data_IN);
        clientThread.Start(clientSocket);
        SendRegisterationPacket();
    }

    public void SendRegisterationPacket()
    {
        Packet p = new Packet(PacketType.Registration, "server");
        p.gData.Add(id);
        clientSocket.Send(p.ToBytes());
    }
}

public class ClientName
{
    public String id;
    public String name;

    public ClientName(String id, String name)
    {
        this.id = id;
        this.name = name;
    }
}

客户:

public static Socket master;
    public string username;
    public static string id;
    private String ip;
    private int port;

    public Client(String username, String ipPortString)
    {
        InitializeComponent();
        this.username = username;
        ip = ipPortString.Split(':')[0];
        port = Convert.ToInt32(ipPortString.Split(':')[1]);
    }
    private void Client_Load(object sender, EventArgs e){}

    public void Start()
    {
        master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        IPEndPoint point = new IPEndPoint(IPAddress.Parse(ip), port);
        try
        {
            master.Connect(point);
        }
        catch
        {
            MessageBox.Show("Fehler beim Verbinden! Code: 0x156f237" + "\n" + "Der Server konnte nicht gefunden werden!");
            Thread.Sleep(1000);
            Start();
        }
        Thread t = new Thread(Data_IN);
        t.Start();
    }

    void Data_IN()
    {
            byte[] buffer;
            int readBytes;

            for (;;)
            {
                buffer = new byte[master.SendBufferSize];
                readBytes = master.Receive(buffer);

                if (readBytes > 0)
                {
                    DataManager(new Packet(buffer));
                }
            }
    }

    static List<String> packetsReceived = new List<string>();
    static TippForm tippFormCache;

    void DataManager(Packet p)
    {
        PacketType type = p.packetType;
        switch (type)
        {
            case PacketType.Registration:
                id = p.gData[0];
                Packet rp = new Packet(PacketType.RegisterName, id);
                rp.gData.Add(username);
                master.Send(rp.ToBytes());
                break;
            case PacketType.Window:
                String windowID = p.gData[0];
                if (windowID == ABCDForm.SERIALAZIE_ID)
                {
                    if (p.senderID == "server")
                    {
                        if (!packetsReceived.Contains(p.packetID))
                        {
                            ABCDForm form = new ABCDForm(id, p.gData[1], p.gData[2], p.gData[3], p.gData[4], p.gData[5]);
                            if (!IsOpened(form))
                            {
                                form.ShowDialog();
                                packetsReceived.Add(p.packetID);
                            }
                        }
                    }
                }
                else if (windowID == OpenAnswerForm.SERIALIZE_ID)
                {
                    if (p.senderID == "server")
                    {
                        if (!packetsReceived.Contains(p.packetID))
                        {
                            OpenAnswerForm form = new OpenAnswerForm(id, p.gData[1]);
                            if (!IsOpened(form))
                            {
                                form.ShowDialog();
                                packetsReceived.Add(p.packetID);
                            }
                        }
                    }
                }
                else if (windowID == TippForm.SERIALIZE_ID)
                {
                    if (p.senderID == "server")
                    {
                        if (!packetsReceived.Contains(p.packetID))
                        {
                            tippFormCache = new TippForm(id, p.gData[1], p.gData[2], p.gData[3], p.gData[4], p.gData[5]);
                            if (!IsOpened(tippFormCache))
                            {
                                tippFormCache.ShowDialog();
                                packetsReceived.Add(p.packetID);
                            }
                        }
                    }
                }
                else if (windowID == SoundForm.SERIALAZIE_ID)
                {
                    if (p.senderID == "server")
                    {
                        if (!packetsReceived.Contains(p.packetID))
                        {
                            SoundForm form = new SoundForm(id, p.gData[1]);
                            if (!IsOpened(form))
                            {
                                form.ShowDialog();
                                packetsReceived.Add(p.packetID);
                            }
                        }
                    }
                }
                else if (windowID == VideoPlayerForm.SERIALIZE_ID)
                {
                    if (p.senderID == "server")
                    {
                        if (!packetsReceived.Contains(p.packetID))
                        {
                            playerForm = new VideoPlayerForm(id);
                            if (!IsOpened(playerForm))
                            {
                                Thread t = new Thread(() => OpenVideoPlayerWithSTA(p));
                                t.SetApartmentState(ApartmentState.STA);
                                t.Start();
                            }
                        }
                    }
                }
                break;
            case PacketType.OpenNewTipp:
                if(tippFormCache != null)
                {
                    tippFormCache.OpenNewTipp();
                }
                break;
            case PacketType.CanDownload:
                if(p.senderID == "server")
                {
                    Uri downloadLink = new Uri(p.gData[0]);

                    String uri = FileTransfer.DownloadFile(downloadLink);

                    Packet replyPacket = new Packet(PacketType.HasDownloaded, id);
                    replyPacket.gData.Add(uri);
                    master.Send(replyPacket.ToBytes());
                }
                break;
            case PacketType.Play:
                if (IsOpened(playerForm))
                {
                    playerForm.Start();
                }
                break;
            case PacketType.TogglePause:
                if (IsOpened(playerForm))
                {
                    playerForm.Pause();
                }
                break;
            case PacketType.Stop:
                if (IsOpened(playerForm))
                {
                    playerForm.Stop();
                }
                break;
        }
    }

    private static void OpenVideoPlayerWithSTA(Packet p)
    {
        playerForm.ShowDialog();
        packetsReceived.Add(p.packetID);
    }

    private static VideoPlayerForm playerForm;

    private static bool IsOpened(Form form)
    {
        FormCollection fc = Application.OpenForms;
        foreach(Form f in fc)
        {
            if(f == form)
            {
                return true;
            }
        }
        return false;
    }

还有我的数据包Class/服务器数据:

[Serializable]
public class Packet
{
    public List<String> gData;
    public int packetInt;
    public bool packetBool;
    public string senderID;
    public PacketType packetType;
    public string packetID;

    public Packet(PacketType packetType, string senderID)
    {
        gData = new List<String>();
        this.senderID = senderID;
        this.packetType = packetType;
        packetID = Guid.NewGuid().ToString();
    }

    public Packet(byte[] bytes)
    {
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream(bytes);

        ms.Position = 0;

        Packet p = (Packet)bf.Deserialize(ms);
        ms.Close();

        gData = p.gData;
        packetBool = p.packetBool;
        packetInt = p.packetInt;
        packetType = p.packetType;
        senderID = p.senderID;
        packetID = Guid.NewGuid().ToString();
    }

    public byte[] ToBytes()
    {
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream();

        ms.Position = 0;

        bf.Serialize(ms, this);
        byte[] bytes = ms.ToArray();
        ms.Close();
        return bytes;
    }

    public static string GetIP4Address()
    {
        IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());

        foreach(IPAddress ip in ips)
        {
            if(ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                return ip.ToString();
            }
        }
        return "127.0.0.1";
    }
}

public enum PacketType
{
    Registration,
    Window,
 /*[0] = FormID
 *
 * ABCD:
 * [1] = Frage
 * [2] = A
 * [3] = B
 * [4] = C
 * [5] = D
 * 
 * OPEN:
 * [1] = Frage
 * 
 * TIPP:
 * [1] = 1. Tipp
 * [2] = 2. Tipp
 * [3] = 3. Tipp
 * [4] = 4. Tipp
 * [5] = 5. Tipp
 * 
 * SOUND:
 * [1] = Uri
 */
    Answer,//[0] = Antwort
    OutWindow,
    RegisterName,
    Play,
    TogglePause,
    Stop,
    OpenNewTipp,
    CanDownload,
    HasDownloaded
}

希望大家能帮帮我。

您在连接到 Internet 的 router/NAT 中激活端口转发。然后你朋友的客户端应该有你的 public IP 地址(互联网提供商的路由器之一,你可以看到这个地址登录到 router/NAT)并且应该将消息发送到特定端口。您转到路由器并配置端口转发。这个假设的本地网络意味着您的网络位于将您连接到 Internet 的路由器后面。