简体   繁体   中英

TCP Sockets - InvalidOperationException

I'm new to networking in C# and I am having some troubles making a basic client - server. The server runs fine, but when the server is up and the client tries to connect it throws the error "the socket must not be bound or connected". Some extra details are that the server and client are being ran on the same computer with exclusiveAddressUse disabled.

Client code:

this.client = new TcpClient(this.settings.GetByName("MasterServerIP").Value, int.Parse(this.settings.GetByName("MasterServerPort").Value)) { ExclusiveAddressUse = false };
this.client.Connect(IPAddress.Parse(this.settings.GetByName("MasterServerIP").Value), int.Parse(this.settings.GetByName("MasterServerPort").Value));
this.writer = new BinaryWriter(this.client.GetStream());
this.reader = new BinaryReader(this.client.GetStream());

Server code:

this.Listener.Start();
TcpClient tcpClient;
while (this.Listener.Server.Connected)
{
tcpClient = this.Listener.AcceptTcpClient();
System.Threading.Thread t = new System.Threading.Thread(() => { this.ProcessClient(tcpClient); }); //Runs the thing on another thread so this can be accepting another client
t.Start();
}

Edit: Even with the connect method call removed, it is still throwing the same error. Any help?

The problem is in the first two lines of the client code:

this.client = new TcpClient(this.settings.GetByName("MasterServerIP").Value, int.Parse(this.settings.GetByName("MasterServerPort").Value)) { ExclusiveAddressUse = false };
this.client.Connect(IPAddress.Parse(this.settings.GetByName("MasterServerIP").Value), int.Parse(this.settings.GetByName("MasterServerPort").Value));

When you call to the constructor on the first line, you're already connecting the TcpClient, so the Connect call afterwards is invalid. Remove it and it will work.

From the docs , the constructor:

Initializes a new instance of the TcpClient class and connects to the specified port on the specified host.

When you create a TCPClient with the host and port, it connects automatically. You don't then need to connect again.

See http://msdn.microsoft.com/en-us/library/System.Net.Sockets.TcpClient(v=vs.110).aspx for details.

With regards to your comment that it's still failing when you remove the connect call, either you're still running the other code or there's something else wrong. The following code runs fine:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace testtcp {
    class Program {
        static void Main(string[] args) {
            TcpClient client = new TcpClient("www.google.com", 80);
            //client.Connect("www.microsoft.com", 80);
        }
    }
}

but, the instant you uncomment the Connect call, you get a SocketException with the expanatory text:

{"A connect request was made on an already connected socket"}

However, that's actually a different error message to the one you're getting, leading us to believe the "there's something else wrong" statement from above.

If you examine the online docs for TcpClient.ExclusiveAddressUse here , you'll notice the following snippet (my bold):

This property must be set before the underlying socket is bound to a client port. If you call Connect , BeginConnect , TcpClient(IPEndPoint) , or TcpClient(String, Int32), the client port is bound as a side effect of the method, and you cannot subsequently set the ExclusiveAddressUse property.

And indeed, the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace testtcp {
    class Program {
        static void Main(string[] args) {
            TcpClient client = new TcpClient("www.google.com", 80) {
                ExclusiveAddressUse = false
            };
        }
    }
}

gives you the exact exception you describe.

So, bottom line, if you want to use ExclusiveAddressUse , don't try to use it with the host-and-port constructor, since that will bind the socket and the attempted property change will then raise an exception. Instead, (as one possibility) use the no-argument constructor, change the property, and then connect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM