2010-05-29 3 views
1

나는 Call of Duty 1의 초기 버전에 대한 IP 금지 도구 작업에 바쁘다. (분명히 이러한 기능은이 버전에서는 구현되지 않았다).같은 포트에있는 서버 폴링 - 스레드와 Java

단일 스레드 응용 프로그램을 완료했지만 여러 서버에서 성능이 충분하지 않아서 스레딩을 구현하려고합니다.

지금 당장 각 서버에는 자체 스레드가 있습니다. Networking 클래스에는 메서드가 있습니다. "GetStatus"-이 메서드는 동기화됩니다. 이 메서드는 DatagramSocket을 사용하여 서버와 통신합니다. 이 방법은 정적이고 동기화되어 있으므로 문제가 발생하지 않고 "주소가 이미 사용 중입니다"라는 예외를 많이받지 않아야합니다.

그러나 두 번째 방법은 "SendMessage"입니다. 이 메서드는 서버에 메시지를 보내도록되어 있습니다. "GetStatus"에서 이미 실행중인 스레드가있을 때 "SendMessage"를 호출 할 수 없다는 것을 어떻게 확인할 수 있습니까? 둘 다 동기화하면 스레드 A가 포트 99999에서 소켓을 열고 "SendMessage"를 호출하는 동안 스레드 B가 동일한 포트에서 소켓을 열고 "GetStatus"를 호출하면 여전히 문제가 발생합니다. (게임 서버는 대개 같은 포트에서 호스팅됩니다.)

나는 정말로 후에 전체 클래스를 동기화하는 방법으로 추측하여 하나의 메서드 만 호출하고 한 번에 하나의 스레드 만 실행할 수 있습니다.

나는이 텍스트에서 분명히 이루고자하는 바를 간절히 원합니다.

도움을 주시면 대단히 감사하겠습니다.

+1

btw, 99999는 유효한 포트가 아닙니다. 포트는 16 비트 부호없는 숫자입니다. – mdma

+0

SendMessage와 GetStatus가 동기화되어 있습니까? – Kiril

+0

포트 99999는 단지 예일뿐입니다. "포트 XXXXX"가 유효한 포트가 아니라고 말했습니까? "Port "은 어떻습니까? – John

답변

2

: 클라이언트와 서버 측 소켓에 대한 소개

는 일 레슨을 참조하십시오.

왜 같은 응용 프로그램에 두 대의 서버가 필요합니까? 두 서버를 별도의 응용 프로그램으로 분리 한 경우 두 서버가 동일한 포트를 사용하려고하면 동일한 문제가 발생합니다. 즉, 각 서버에 전용 포트를 사용해야합니다. 스레딩에 실제로 문제가있는 경우이를 수정하는 방법에 대한 아이디어를 아래에서 읽으십시오. 두 개의 스레드가 같은 클래스의 제대로 동기화 방법을 실행하기위한

그것은 불가능 ... 당신이 적절한 동기화이있는 경우 다음 설명을하는지 체험 할 수있는 방법은 없습니다. 다음은 클래스가 어떻게 보일지입니다 : 동일한 Networking 예를에 이러한 방법 를 호출하고 그래서 한

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 클래스의 별도의 인스턴스가 없습니다), 그러면 어떤 문제도 보지 않아야합니다.,

첫째는 에 동기화 방법이 호출 인터리브하기 위해 동일한 개체에 대한 수 없습니다 : 여기에 synchronized 키워드가 당신을 위해 무엇이다. 한 스레드가 하나의 개체에 대해 동기화 된 메서드를 실행하는 경우 다른 모든 스레드는 동일한 개체 블록 (실행을 일시 중단)에 대해 메서드를 동기화합니다. 스레드가 개체와 함께 완료 될 때까지 동기화됩니다.

둘째, 동기화 방법 종료하면 자동으로 설정하면 일어난다-전과 동일한 오브젝트의 동기화 방법 중 어느 후속 호출과 관계. 이렇게하면 객체 상태에 대한 의 변경 사항이 모든 스레드에 대해 으로 표시됩니다. (ref)

당신은 당신이 동기화 문을 사용할 필요가 다음 네트워킹 클래스의 모든 인스턴스에서 메소드의 동기화를 원한다면 : [I]가 여전히 문제 드릴 것입니다

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

UDP 소켓에서만 'accept'를 호출하지 않고 TCP 소켓에서만 'accept'를 호출합니다. –

+0

맞아요 - 데이터 그램 소켓이라고 생각하지 않았습니다. – mdma

2

을 스레드 A 이 포트 99999에서 소켓을 열고 스레드 B 이 소켓 을 열고 "GetStatus"를 호출하는 동안 "SendMessage"를 호출하는 을 열면?

여기에는 두 가지 개별적인 문제가 있습니다. (99999가 유효한 포트 번호가 아님을 넘어서) #

UDP는 멀티플렉싱 된 일대 다 스타일 커뮤니케이션을 의미합니다. 단일 소켓을 열고 그 단일 소켓을 사용하여 원하는만큼의 서버와 통신 할 수 있습니다. 소켓에 대한 읽기 및 쓰기 작업은 응용 프로그램 관점에서 볼 때 아무런 문제가 없으므로 하나의 스레드 전송 및 동일한 소켓에서의 다른 수신 또는 동시에 전송하려는 두 개의 스레드에 대해 동기화에 대해 걱정할 필요가 없습니다. UDP 소켓을 보내면 N 바이트의 데이터를 응용 프로그램의 메모리 공간에서 OS 커널의 메모리 공간에있는 버퍼로 복사하는 시스템 호출을 호출하고 커널은 해당 데이터를 대기열에있는 UDP 패킷으로 어셈블합니다 전송을 위해 - 응용 프로그램에 원자 적으로 보이는 방식으로 모두. 역순을 제외하고는 UDP 소켓에서 읽을 때도 마찬가지입니다. 별개의 패킷은 커널의 수신 버퍼에 존재하며 응용 프로그램이 소켓을 읽을 때 해당 패킷의 데이터는 커널 버퍼에서 응용 프로그램의 버퍼로 원자 적으로 복사됩니다 (읽기 작업 당 하나의 패킷).

두 번째 문제는 특정 서버로 들어오고 나가는 데이터를 관리하는 것입니다. 해당 서버에 대한 상태/상태를 유지 관리하는 서버 당 하나의 스레드를 갖고 싶어하는 것 같습니다. 전송할 때 동기화에 대해 전혀 걱정할 필요가 없습니다. 모든 스레드는 동일한 소켓에서 전송할 수 있으며 동기화는 OS 커널에 의해 효과적으로 처리됩니다.

그러나 수신은 완전히 다른 문제입니다. 소켓에서 들어오는 패킷을 읽고 역 다중화하는 유일한 작업이있는 스레드를 사용하는 것이 좋습니다. 각 서버 스레드는 수신 스레드가 수신 패킷을 복사하는 스레드 안전 큐를 갖습니다. 그런 다음 각 서버 스레드는 자체 수신 패킷 대기열에서 패킷을 읽는 것 이외의 다른 것에 대해 걱정할 필요가 없습니다. 소켓에서 읽는 것을 모두 처리 할 필요가 없습니다.

관련 문제