2012-01-30 2 views
3

편집 : Ik 길지만 누구든지 소켓을 프로그래밍하는 방법을 알고 있습니까?Java 소켓 : 서버 입력 스트림이 클라이언트 출력 스트림에서 읽히지 않습니까?

내 문제는 나를 조금 혼란스럽게합니다. 한 대의 컴퓨터에서 서버를 실행하고 다른 컴퓨터에서 클라이언트를 연결했습니다. 클라이언트에서 콘솔로 메시지를 입력하여 보내면 서버가 메시지를받지 못하는 것입니다. 왜 내가 지난 3 시간 동안 콘솔에 인쇄를 테스트했기 때문에 아무도 알지 못합니다. 알아낼 수 없기 때문입니다. 나는 소켓에 비교적 새롭기 때문에 내가 단지 바보가된다면 너무 가혹하지는 마라.

Heres는 클라이언트 측에 대한 내 코드 :

import java.io.IOException; 
import java.net.*; 

public class MultipleSocketServer { 

public static Socket connection; 
public static String name = "Tyler's Server"; 
public static int limit = 2; 
public static Thread[] clients = new Thread[limit]; 
public static int current = 0; 
public static int port = 25565; 
public static String[] connected = {"", ""}; 
public static ServerSocket socket; 

public static void main(String[] args) { 
    System.out.println("Server starting..."); 
    try { 
     ServerSocket socket = new ServerSocket(port); 
     while(true) { 
      Socket connection = socket.accept(); 
      String ip = connection.getRemoteSocketAddress().toString().substring(1, 13); 
      loop: 
      for(int i = 0; i < connected.length; i++) { 
       if(connected[0].equals(ip) || connected[1].equals(ip)) { 
        break loop; 
       }else if(!connected[i].equals(ip)) { 
        connected[i] = ip; 
        System.out.println(ip); 
        MultiServer_Client client = new  MultiServer_Client(connection, i); 
        Thread run = new Thread(client); 
        run.start(); 
        break loop; 
       } 
      } 
     } 
    } catch (IOException e1) { 
     System.out.println("Could not bind server on: " + port); 
     System.exit(-1); 
    } 
} 
} 

그리고 여기에 연결된 각 클라이언트를 처리하는 내 코드입니다 : 여기

import java.net.*; 
import java.util.Scanner; 
import java.io.*; 

public class SocketClient { 

public static void main(String [] args) { 
    String host = "************"; 
    int port = 25565; 

    StringBuffer instr = new StringBuffer(); 
    String TimeStamp; 
    System.out.println("SocketClient initialized"); 

    try { 
     InetAddress address = InetAddress.getByName(host); 
     Socket connection = new Socket(address, port); 

     BufferedOutputStream bos = new  BufferedOutputStream(connection.getOutputStream()); 
     OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII"); 

     Scanner scan = new Scanner(System.in); 
     String message = scan.nextLine(); 

     TimeStamp = new java.util.Date().toString(); 
     String process = "Server called on " + host + ":" + port + " at " + TimeStamp + ": " + message + (char) 13; 

     osw.write(process); 
     osw.flush(); 

     BufferedInputStream bis = new BufferedInputStream(connection.getInputStream()); 

     InputStreamReader isr = new InputStreamReader(bis, "US-ASCII"); 

     int c; 
     while ((c = isr.read()) != 13) 
      instr.append((char) c); 

     connection.close(); 
     System.out.println(instr); 

    } catch (UnknownHostException e) { 
     System.err.println("UnknownHostException: " + e); 
    } catch (IOException e) { 
     System.err.println("IOExcepion: " + e); 
    } 
} 
} 

서버에 클라이언트를 연결하는 코드는 다음과 같습니다

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.net.Socket; 

public class MultiServer_Client implements Runnable { 

public String time; 
public Socket client; 
public StringBuffer process = new StringBuffer(); 

public BufferedInputStream inputStream; 
public InputStreamReader reader; 

public BufferedOutputStream outputStream; 
public OutputStreamWriter writer; 

public boolean connected = true; 

public int ID; 

public MultiServer_Client(Socket connection, int i) { 
    client = connection; 
    ID = i; 
    try { 
     inputStream = new BufferedInputStream(client.getInputStream()); 
     reader = new InputStreamReader(inputStream); 

     outputStream = new BufferedOutputStream(client.getOutputStream()); 
     writer = new OutputStreamWriter(outputStream, "US-ASCII"); 
    } catch (IOException e) { 
     System.out.println("IOException: " + e); 
    } 
    System.out.println("Client connected..."); 
    write("Connected to " + MultipleSocketServer.name); 
} 

public void run() { 
    while(connected) { 
     write("hi"); 
    } 
    System.out.println("Disconnecting client..."); 
} 

public void write(String authen) { 
    try { 
     time = new java.util.Date().toString(); 
     String message = time + ": " + authen + (char) 13; 
     writer.write(message); 
     writer.flush(); 
    } catch (IOException e) { 
     connected = false; 
     MultipleSocketServer.connected[ID] = ""; 
    } 
} 

public void read() { 
    //read from client 
    int character; 
    process = new StringBuffer(); 
    try { 
     while ((character = reader.read()) != 13) { 
      process.append((char) character); 
     } 
     System.out.println(process); 
     process.delete(0, process.length()); 
    } catch (IOException e) { 
     connected = false; 
     MultipleSocketServer.connected[ID] = ""; 
    } 
} 
} 

나는별로 도움이되지 않는다. 내가 말했듯이, 나는 소켓에 새로운 사람이 아무 문제가있을 것 같습니다 ... 감사 :

+1

당신은 예외 예외 자체를 로그인하지 않고 발생할 때마다 자동으로 해제 될 것으로 보인다. 서버가 클라이언트 연결을 끊기 때문에 예외가 코드에서 발생할 수 있습니까? – Dawood

+0

서버의 write() 및 read() 메소드에서 코드가 예외를 발생 시키면 클라이언트를 닫을 때와 마찬가지로 서버가 종료됩니다. 어떤 예외가있을 때 클라이언트 클래스의 모든 것을 인쇄하고 있습니다. 나는 정말로 hahaha 여기에서 비빈다. 그래도 조언 주셔서 감사합니다. – MrDrProfessorTyler

+0

또한 socket.accept()를 반복하여 클라이언트를 서버에 연결하면 read() 및 write()가 제대로 작동하고 연결이 완벽하게 작동하지만 다른 클라이언트와 컴퓨터를 추적 할 수 없습니다 무한대의 클라이언트가 서버에서 실행될 수 있습니다. 고칠 방법이 없나요? – MrDrProfessorTyler

답변

6

귀하의 코드에 문제가 귀하의 통신 프로토콜은 "소켓"되지 않습니다. 서버가 "hi"를 쓸 기회가 오기 전에 소켓을 효과적으로 닫고 있습니다.

이 문제를 디버깅하려면 프로그램의 복잡성을 줄이려합니다. 프로그램에는 의미 나 문제가없는 여러 가지가 있습니다.

그래서 소켓에 약간의 배경이 있습니다. 두 가지 유형의 소켓이 있습니다. "ServerSocket"과 "Socket"ServerSocket은 비서와 같습니다. 그것의 유일한 임무는 전화를 듣고 그들을 전달하는 것입니다. 이것은 "수용"이하는 것입니다. 클라이언트가 연결되기 전에 accept()는 연결을 수신 할 때까지 차단됩니다. 클라이언트가 연결되면 accept는 연결을 나타내는 Socket을 반환합니다.

정규 소켓은 모든 작업이 이루어지는 곳입니다. 당신은 전화 연결로 생각할 수 있습니다. OutputStream을 사용하여 원격으로 누군가와 대화하고 InputStream을 사용하여 청취 할 수 있습니다. 문제는 두 소켓이 통신 할 수 있도록 일종의 통신 (프로토콜이라고 함)을 만들어야한다는 것입니다.

명령을 구분하는 방법을 알아야합니다. 길이가 한정된 프로토콜을 원하거나 메시지 끝에 특수 문자 (현재있는 것)를 사용할 수있는 경우 고정 길이 번호와 데이터를 전달할 수 있습니다. 빠르고 더러운 경우에는 종종 후자를 개행 문자로 사용합니다. 가장 쉬운 방법은 쓰기 용으로 PrintWriter를 사용하고 읽기 용으로 스캐너를 사용하는 것입니다.

다음 단계는 클라이언트와 서버의 통신 패턴을 파악하는 것입니다. 공을 앞뒤로 통과하는 것으로 생각하면됩니다. 클라이언트가 무언가를 말하면 상대방은 청취해야합니다 (반대의 경우도 마찬가지입니다).

일단 프로토콜과 논리를 알아 내면 서버가 한 번에 둘 이상의 클라이언트를 처리 할 수 ​​있도록 서버 측을 별도의 스레드 (작업자 패턴이라고 함)로 처리하기위한 논리를 이동할 수 있습니다. 더 나아 가기를 원한다면, 쓰레드 풀이있는 reactor를 구현하여 서버가 쓰레드를 다 쓰지 않도록 할 수 있습니다.하지만 아마도 다른 날/질문 일 것입니다.

나는 소켓에 자바 튜토리얼 다음 추천 : http://docs.oracle.com/javase/tutorial/networking/sockets/index.html

+0

덕분에 코드를 조금 수정하고 더 효율적으로 만들 수있었습니다. 클라이언트쪽에 큰 문제가 있다고 생각했습니다. 문자열을 쓰고 읽을 때마다 계속 서버에 다시 연결하는 것처럼 보입니다. 감사. – MrDrProfessorTyler