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);

我不确定它是否是最简洁的解决方案,但它运作良好,所以谢谢你的回答:)

4

2 回答 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 聊天示例

于 2013-02-12T17:57:09.880 回答
1

如果您知道要连接的计算机的名称,那么您可以使用 System.Net.DNS 轻松找到其 IP。

var ip = System.Net.Dns.GetHostEntry("JacksLaptop"); 
string ipString = ip.AddressList[0].ToString();

您认为您正在使用的 IP 可能不是该阵列位置 0 中的 IP,因此请注意这一点。

于 2013-02-12T18:01:17.457 回答