views:

58

answers:

3

Hi there.

I'm currently busy working on an IP ban tool for the early versions of Call of Duty 1. (Apparently such a feature wasn't implemented in these versions).

I've finished a single threaded application but it won't perform well enough for multiple servers, which is why I am trying to implement threading.

Right now, each server has its own thread. I have a Networking class, which has a method; "GetStatus" -- this method is synchronized. This method uses a DatagramSocket to communicate with the server. Since this method is static and synchronized, I shouldn't get in trouble and receive a whole bunch of "Address already in use" exceptions.

However, I have a second method named "SendMessage". This method is supposed to send a message to the server. How can I make sure "SendMessage" cannot be invoked when there's already a thread running in "GetStatus", and the other way around? If I make both synchronized, I will still get in trouble if Thread A is opening a socket on Port 99999 and invoking "SendMessage" while Thread B is opening a socket on the same port and invoking "GetStatus"? (Game servers are usually hosted on the same ports)

I guess what I am really after is a way to make an entire class synchronized, so that only one method can be invoked and run at a time by a single thread.

Hope that what I am trying to accomplish/avoid is made clear in this text.

Any help is greatly appreciated.

A: 

I think you may be misunderstanding how sockets work and getting client and server ends of sockets confused. If you're sending a message, that usually done from a client socket. These are not bound to a static port number - it's the server socket (the one you call accept() on) that is bound to a specific port.

You can have as many clients as you need (up to some reasonable limit - there is a max of ca. 60,000 client connections) from any one network interface.

For an introduction to client and server-side sockets, see the Sun Lesson: All About Sockets

mdma
You don't call `accept` on a UDP socket, only on a TCP socket.
Robert S. Barnes
Right - I didn't see that it was a datagram socket.
mdma
+2  A: 

Right now, each server has its own thread.

Why do you need two servers in the same application?!? If you break both of the servers out into separate application, then you're still going to have the same issue if both of them try to use the same port... i.e. you have to dedicate a port for each server. If it's really a problem with the threading, then read below for ideas on how to fix this.

It's not possible for two threads to execute properly synchronized methods of the same class... if you have proper synchronization then there is no way to experience what you're describing. Here is what your class should look like:

class Networking 
{
    public synchronized Status getStatus() {
        Status stat =  new Status();
        // ...
        // Get status logic
        // ...
        return stat;// return the status
    }

    public synchronized void sendMessage(Message msg) {
        // ...
        // Send the message logic
        // ...
    }
}

So as long as you're invoking those methods on the same Networking instance (i.e. you don't have a separate instance of the Networking class for each thread), then you should not see any issues. Here is what the synchronized keyword does for you:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads. (ref)

If you want to have synchronization of the methods across all of the instances of the Networking class then you need to use synchronization statements:

class Networking 
{
    private static final Object lock = new Object();

    public synchronized Status getStatus() {
        synchronized(lock){
            Status stat =  new Status();
            // ...
            // Get status logic
            // ...
            return stat;// return the status
        }
    }

    public synchronized void sendMessage(Message msg) {
        synchronized(lock){
            // ...
            // Send the message logic
            // ...
        }
    }
}
Lirik
+2  A: 

will [ I ] still get in trouble if Thread A is opening a socket on Port 99999 and invoking "SendMessage" while Thread B is opening a socket on the same port and invoking "GetStatus"?

There are two separate issues here. ( beyond the fact that 99999 is not a valid port # )

UDP by it's nature is meant for multiplexed one to many style communications. You can open a single socket and use that single socket to communicate with as many servers as you want. You don't have to worry about synchronization in the sense of one thread sending and another receiving on the same socket or two threads trying to send simultaneously because the read and write operations to the socket are atomic from the applications point of view. When you send on a UDP socket you are invoking a system call which copies N bytes of data from the application's memory space into a buffer in the OS kernel's memory space, and the kernel assembles that data into a UDP packet which is put on a queue for sending - all in a manner which looks atomic to the application. The same occurs when reading from a UDP socket except in reverse; distinct packets exist in a receive buffer in the kernel and when your application reads the socket the data in those packets is atomically copied from the kernel buffer into your application's buffer, one packet per read operation.

The second issue is managing incoming and outgoing data to specific servers. It sounds like you want to have one thread per server which maintains state / status regarding that server. When sending, you don't have to worry about synchronization at all. All the threads can send from the same socket and synchronization is effectively handled by the OS kernel.

However, receiving is a completely different issue. I would recommend having one thread whose only job is to read incoming packets off the socket and de-multiplex them. Each server thread would have a thread safe queue into which the reader thread would copy the incoming packets. Then each server thread doesn't have to worry about anything other than reading packets out of it's own incoming packets queue - it doesn't have to deal with reading from the socket at all.

Robert S. Barnes