在网络上建立TCP/IP客户端和服务器进行通信的设置

7
我想了解一些套接字编程知识,我发现TcpListener和TcpClient对于初学者来说稍微容易一些。我想要实现的基本目标是在我的笔记本电脑和同一网络的另一台笔记本电脑上运行一个小表单,并使它们可以相互通信,即向彼此发送一串文本。一旦我实现了这个目标,我就会进一步开发它 :)
到目前为止,我已经使用msdn和互联网上找到的各种指南创建了客户端和服务器程序。当它们都在一台笔记本电脑上运行时,它们可以相互通信,但当我将客户端移动到另一台笔记本电脑上时,我一无所获。我认为我的主要问题是我不太理解客户端如何找到服务器IP,因为我可以硬编码它,但当我在另一个时间回来时,我确定IP地址已经改变了。有没有更动态地使两者连接以涵盖IP地址的更改的方法?
我的当前客户端代码:
    public void msg(string mesg)
    {
        lstProgress.Items.Add(">> " + mesg);
    }

    private void btnConnect_Click(object sender, EventArgs e)
    {
        string message = "Test";
        try
        {
            // Create a TcpClient.
            // Note, for this client to work you need to have a TcpServer 
            // connected to the same address as specified by the server, port
            // combination.
            Int32 port = 1333;
            TcpClient client = new TcpClient(<not sure>, port); //Unsure of IP to use.

            // Translate the passed message into ASCII and store it as a Byte array.
            Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);

            // Get a client stream for reading and writing.
            //  Stream stream = client.GetStream();

            NetworkStream stream = client.GetStream();

            // Send the message to the connected TcpServer. 
            stream.Write(data, 0, data.Length);

            lstProgress.Items.Add(String.Format("Sent: {0}", message));

            // Receive the TcpServer.response.

            // Buffer to store the response bytes.
            data = new Byte[256];

            // String to store the response ASCII representation.
            String responseData = String.Empty;

            // Read the first batch of the TcpServer response bytes.
            Int32 bytes = stream.Read(data, 0, data.Length);
            responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
            lstProgress.Items.Add(String.Format("Received: {0}", responseData));

            // Close everything.
            stream.Close();
            client.Close();
        }
        catch (ArgumentNullException an)
        {
            lstProgress.Items.Add(String.Format("ArgumentNullException: {0}", an));
        }
        catch (SocketException se)
        {
            lstProgress.Items.Add(String.Format("SocketException: {0}", se));
        }
    }

我的当前服务器代码:

    private void Prog_Load(object sender, EventArgs e)
    {
        bw.WorkerSupportsCancellation = true;
        bw.WorkerReportsProgress = true;
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

        if (bw.IsBusy != true)
        {
            bw.RunWorkerAsync();
        }
    }

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        lstProgress.Items.Add(e.UserState);
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        if ((worker.CancellationPending == true))
        {
            e.Cancel = true;
        }
        else
        {
            try
            {
                // Set the TcpListener on port 1333.
                Int32 port = 1333;
                //IPAddress localAddr = IPAddress.Parse("127.0.0.1");
                TcpListener server = new TcpListener(IPAddress.Any, port);

                // Start listening for client requests.
                server.Start();

                // Buffer for reading data
                Byte[] bytes = new Byte[256];
                String data = null;

                // Enter the listening loop.
                while (true)
                {
                    bw.ReportProgress(0, "Waiting for a connection... ");
                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.
                    TcpClient client = server.AcceptTcpClient();
                    bw.ReportProgress(0, "Connected!");

                    data = null;

                    // Get a stream object for reading and writing
                    NetworkStream stream = client.GetStream();

                    int i;

                    // Loop to receive all the data sent by the client.
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Translate data bytes to a ASCII string.
                        data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                        bw.ReportProgress(0, String.Format("Received: {0}", data));

                        // Process the data sent by the client.
                        data = String.Format("I Have Received Your Message: {0}", data);

                        byte[] mssg = System.Text.Encoding.ASCII.GetBytes(data);

                        // Send back a response.
                        stream.Write(mssg, 0, mssg.Length);
                        bw.ReportProgress(0, String.Format("Sent: {0}", data));
                    }

                    // Shutdown and end connection
                    client.Close();
                }
            }
            catch (SocketException se)
            {
                bw.ReportProgress(0, String.Format("SocketException: {0}", se));
            }
        }
    }

你可能已经注意到,我对此完全是新手,如果有更好的实现方法,我很乐意学习!提前感谢任何帮助 :)

下面是我的解决方案,多亏了以下答案:

private String IPAddressCheck()
    {
        var IPAddr = Dns.GetHostEntry("HostName");
        IPAddress ipString = null;

        foreach (var IP in IPAddr.AddressList)
        {
            if(IPAddress.TryParse(IP.ToString(), out ipString) && IP.AddressFamily == AddressFamily.InterNetwork)
            {
                break;
            }
        }
        return ipString.ToString();
    }

    private void btnConnect_Click(object sender, EventArgs e)
    {
        string message = "Test";
        try
        {
            Int32 port = 1337;  
            string IPAddr = IPAddressCheck();
            TcpClient client = new TcpClient(IPAddr, port);

我不确定这是否是最简洁的解决方案,但它运行良好,感谢您的答案 :)


1
如果您正在寻找一般的代码审查,我建议您发布到CodeReview.SE。如果您正在寻找特定问题的答案(“有没有办法以更动态的方式连接这两个部分以包含不断变化的IP?”),则应将代码缩小到仅涉及您遇到问题的区域。 - Bobson
抱歉,Bobson。我以后会让我的代码片段更短,更相关!感谢您的建议 :) - Jack Eker
2个回答

1

我不太确定你所说的“更动态地包含变化的IP”是什么意思。先猜测一下,你当前可能有以下代码:

TcpClient client = new TcpClient(<not sure>, port); //Unsure of IP to use.

你可以在同一台机器上运行客户端和服务器,并使用本地回环IP地址:

IPAddress.Parse("127.0.0.1")

如果它们在不同的机器上运行,只需将127.0.0.1替换为服务器使用的任何IP地址(这假设没有NAT或防火墙阻止)。
如果您不想使用IP地址,您可以始终使用主机名(这可能被认为更“动态”),但这需要适当配置的DNS设置(对于本地系统)。
TcpClient client = new TcpClient("testMachine1", 1333);

很高兴学习套接字编程。我是网络库networkcomms.net的开发者,如果您想在学习的同时倒推一个工作示例,请查看这个wpf chat example。请注意保留HTML标签。

非常感谢,如我对原帖所做的修改所示,我已使用主机名获取IP并将其指向该IP。非常感谢你指引了我正确的方向,我一定会查看你的工作示例以学习更多! - Jack Eker

1
如果您知道要连接的计算机名称,则可以使用System.Net.DNS轻松找到其IP。
var ip = System.Net.Dns.GetHostEntry("JacksLaptop"); 
string ipString = ip.AddressList[0].ToString();

你认为自己使用的 IP 可能不是数组中位置 0 上的 IP,因此请注意。


谢谢你的帮助,我也采纳了你的建议来解决问题。我认为我已经实现了一种确保从AddressList中获取正确IP的方法,你可以在我的编辑中看到我的尝试 :) - Jack Eker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接