2010-05-29 2 views
1

В настоящее время я занят работой над инструментом запрета IP для ранних версий Call of Duty 1. (По-видимому, такая функция не была реализована в этих версиях).Опрос серверов в одном порту - Темы и Java

Я закончил однопоточное приложение, но он не будет работать достаточно хорошо для нескольких серверов, поэтому я пытаюсь реализовать потоки.

Прямо сейчас, каждый сервер имеет свою собственную нить. У меня есть класс Networking, который имеет метод; «GetStatus» - этот метод синхронизирован. Этот метод использует DatagramSocket для связи с сервером. Поскольку этот метод статичен и синхронизирован, я не должен беспокоиться и получать целую кучу исключений «Адрес уже в использовании».

Однако у меня есть второй метод «SendMessage». Этот метод должен отправить сообщение на сервер. Как я могу убедиться, что «SendMessage» не может быть вызван, когда уже есть поток, запущенный в «GetStatus», и наоборот? Если я сделаю оба синхронизированных, у меня все равно возникнут проблемы, если Thread A откроет сокет на порте 99999 и вызовет «SendMessage», а Thread B откроет сокет на том же порту и вызовет «GetStatus»? (Игровые серверы обычно размещаются на одних и тех же портах)

Я думаю, что я действительно хочу, чтобы весь класс синхронизировался, так что только один метод можно вызвать и запустить за один раз одним потоком.

Надеюсь, что то, что я пытаюсь выполнить/избежать, излагается в этом тексте.

Любая помощь очень ценится.

+1

btw, 99999 не является допустимым портом - порты представляют собой 16-разрядные номера без знака – mdma

+0

Что такое синхронизация SendMessage и GetStatus? – Kiril

+0

Порт 99999 был всего лишь примером, вы могли бы сказать мне, что «Порт XXXXX» не является допустимым портом, если я написал это? Что относительно "Порт "? – John

ответ

2

Прямо сейчас, каждый сервер имеет свой собственный поток.

Зачем вам два сервера в одном приложении?!? Если вы разбьете оба сервера на отдельное приложение, у вас все равно будет такая же проблема, если оба из них попытаются использовать один и тот же порт ... т. Е. Вы должны выделить порт для каждого сервера. Если это действительно проблема с потоковой обработкой, то читайте ниже, чтобы узнать, как это исправить.

Это не возможно для двух потоков для выполнения правильно синхронизированные методы одного и того же класса ... если у вас есть надлежащей синхронизации, то нет никакого способа, чтобы испытать то, что вы описываете. Вот то, что ваш класс должен выглядеть следующим образом:

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 
     // ... 
    } 
} 

Так до тех пор, как вы вызываете эти методы на том же Networking например (т.е. не имеет отдельный экземпляр класса Networking для каждого потока), тогда вы не должны видеть никаких проблем.Вот что synchronized ключевое слово делает для вас:

Во-первых, это не возможно для двух вызовов синхронизированных методов на тот же объект чередовать. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые ссылаться на синхронизированные методы для того же самого блока объекта (приостановить исполнение) до первого нити выполняется с объектом.

Во-вторых, когда выходит синхронизированные метод, он автоматически устанавливает случается, прежде чем отношения с любым последующим вызовом синхронизированного метода для того же самого объекта . Это гарантирует, что изменения к состоянию объекта видны ко всем потокам. (ref)

Если вы хотите иметь синхронизацию методов во всех экземпляров класса сетей, то вы должны использовать операторы синхронизации:

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 
      // ... 
     } 
    } 
} 
0

Я думаю, что вы можете не понимать, как работают сокеты, и сбивать с толку клиентские и серверные концы сокетов. Если вы отправляете сообщение, которое обычно выполняется из клиентского сокета. Они не привязаны к статическому номеру порта - это сокет сервера (тот, который вы вызываете accept()), привязанный к определенному порту.

У вас может быть столько клиентов, сколько вам нужно (до некоторого разумного предела - максимально 60 000 клиентских подключений) от любого сетевого интерфейса.

Для введения в клиентских и серверных сокетов см Солнца Урок: All About Sockets

+0

Вы не вызываете 'accept' в UDP-сокете, только в сокете TCP. –

+0

Правильно - я не видел, что это сокет для датаграммы. – mdma

2

будет [I] до сих пор попасть в беду если Thread A открывает гнездо на порте 99999 и , вызывая «SendMessage», а Thread B открывает сокет на том же порту и вызывает «GetStatus»?

Здесь есть две отдельные проблемы. (за исключением того факта, что 99999 не является допустимым портом #)

UDP по своей природе предназначен для мультиплексирования сообщений одного типа. Вы можете открыть один сокет и использовать этот единственный сокет для связи с таким количеством серверов, сколько хотите. Вам не нужно беспокоиться о синхронизации в смысле отправки потока и другого приема в том же сокете или двух потоках, которые пытаются отправить одновременно, поскольку операции чтения и записи в сокет являются атомарными с точки зрения приложений. Когда вы отправляете в сокет UDP, вы вызываете системный вызов, который копирует N байтов данных из пространства памяти приложения в буфер в ядре памяти ОС, а ядро ​​собирает эти данные в пакет UDP, который помещается в очередь для отправки - все в порядке, который выглядит атомарно для приложения. То же самое происходит при чтении из гнезда UDP, кроме как в обратном порядке; в буфере приема в ядре присутствуют разные пакеты, и когда ваше приложение считывает сокет, данные в этих пакетах атомарно копируются из буфера ядра в буфер приложения, один пакет на операцию чтения.

Вторая проблема заключается в управлении входящими и исходящими данными на определенные серверы. Похоже, вы хотите иметь один поток на сервере, который поддерживает состояние/статус в отношении этого сервера. При отправке вам вообще не нужно беспокоиться о синхронизации. Все потоки могут отправлять из одного сокета, и синхронизация эффективно обрабатывается ядром ОС.

Однако получение является совершенно другой проблемой. Я бы рекомендовал иметь один поток, единственное задание которого - считывать входящие пакеты с сокета и декомплексировать их. Каждый поток сервера должен иметь поточную безопасную очередь, в которую поток считывателя будет копировать входящие пакеты. Затем каждому потоку сервера не нужно беспокоиться ни о чем другом, кроме чтения пакетов из собственной очереди входящих пакетов, - ему вообще не приходится разбираться в чтении из сокета.

Смежные вопросы