프로그램을 통해 실제 개념을 확립한 후에는 이제 원래의 질문인 소켓이 무엇인지로 돌아가야 합니다. 소켓은 컴퓨터 통신을 구현하는 방법이지만 가장 이해하기 쉬운 방법은 무엇입니까?
BrUCe Eckel은 자신의 저서 "Java 프로그래밍 사고"에서 소켓에 대해 설명했습니다.
소켓은 연결의 "터미널"을 표현하는 소프트웨어 추상화입니다. 두 기계 사이. 주어진 연결에 대해 각 시스템에는 소켓이 있습니다. 또는 "케이블"의 각 끝이 소켓에 연결되어 있는 가상 "케이블"을 상상할 수 있습니다. 물론 물리적 하드웨어와 머신 간의 케이블 연결은 전혀 알려져 있지 않습니다. 추상화의 전체 목적은 우리가 알 필요가 없는 세부 사항을 알지 못하게 하는 것입니다.
내가 이해한 바에 따르면 추상적인 용어로 소켓은 전화 수신기입니다. 당신과 대화하고 있는 사람도 하나를 갖고 있습니다. 그러나 한 사람의 수신자는 ServerSocket이고 다른 사람의 수신자는 Socket입니다. 누가 ServerSocket이고 누가 Socket인지는 중요하지 않습니다. 왜냐하면 클라이언트와 서버는 본질적으로 있기 때문입니다. 두 사람이 대화하는 중 두 개의 이어피스를 집으면 채널이 형성됩니다. 이 채널이 열려 있는지 여부는 양쪽이 이어피스를 집었는지 여부에 따라 달라집니다. 삑삑 소리만 들려서 채널이 다르다는 것을 확인합니다. 여기서 수화기를 드는 과정은 채널이 설정된 후, 즉 모두가 수화기를 든 후 소켓 초기화 과정입니다. 채널 끝에서 대화를 시작할 수 있습니다. 여기에는 A가 B와 대화하고, B가 응답하고, B가 A와 대화하고, A가 듣는 프로세스가 두 개 더 있습니다. 이 두 프로세스는 두 라인을 통해 완료됩니다. 스트림은 전송의 모든 세부 사항을 숨기므로 통신 당사자 모두가 전송하는 것은 인코딩이 아니라 사운드라고 생각하게 됩니다.
이전에 작성된 서버 측 프로그램은 실제로 단일- 클라이언트에 대한 서버의 처리 메커니즘은 동시에 하나의 연결만 처리할 수 있다는 것입니다. 동시에 요청하는 여러 연결이 있는 경우 이러한 프로그램은 한 클라이언트만 연결 요청을 한다는 것을 보장할 수 없기 때문에 네트워크의 여러 연결을 처리할 수 없습니다. 다중 클라이언트 연결에 대처하기 위해 차단 방법을 사용하는 속도는 느릴 것으로 예상됩니다.
이로 인해 다중 연결 지향 버전이 탄생하게 되었습니다.
해결해야 할 문제는 클라이언트 연결을 처리하는 것이므로 우리의 작업은 프로그램을 수정하는 것뿐입니다. , 연결 요청을 감지한 후 즉시 스레드를 생성하여 처리한 후 계속해서 다음 연결 요청을 수신합니다. 따라서 HandleConnection의 원래 코드만 그대로 두면 자동으로 의 실행 코드에 배치될 수 있습니다. 새로운 스레드를 생성하기 위한 코드를 handlerConnection에 추가할 수 있습니다. 매우 간단합니다.
이전 글과 동일한 스타일, 각 부분의 코드 내용을 살펴보겠습니다.
먼저 이 멀티스레드 버전에 대한 MultiThreadRemoteFileServer 클래스를 생성합니다
이 클래스의 정의를 살펴보세요
import java.io.*;
import java.net.*;
public class MultiThreadRemoteFileServer{
PRotected int listeningPort;
public MultiThreadRemoteFileServer(int aListenPort){
}
public static void main(String[] args) {
}
public void acceptConnections( ) {
}
public void handlerConnection(Socket receivedConnection) {
}
}
은 RemoteFileServer와 거의 동일합니다. 유일한 차이점은 지금 만든 클래스입니다. 생성자는 다음과 같습니다. Listening 포트 번호를 스스로 결정할 수 있도록 추가되었습니다.
public MultithreadedRemoteFileServer(int aListenPort) {
listenPort = aListenPort;
}
보자. main()에서 먼저
public static void main(String[] args) {
MultithreadedRemoteFileServer server = new MultithreadedRemoteFileServer(3000);
server.acceptConnections();
}
차이점은 없으며 포트 번호가 기본 프로그램 생성 시 지정된다는 점을 제외하면 RemoteFileServer의 main() 함수와 동일합니다.
우리가 주로 우려하는 변경 사항은 뒤에 있습니다
이제 acceptConnection 리스너 프로그램을 살펴보세요
public void acceptConnections() {
try {
ServerSocket server = new ServerSocket( ListenPort, 5); //서버 소켓을 생성할 때 추가 매개변수가 있다는 것을 알고 계셨나요? 이 매개변수는 동시에 적용할 수 있는 최대 연결 수를 지정하는 데 사용됩니다. 기본값은 50소켓comingConnection = null;
while(true) {
incomingConnection = server.accept();
handleConnection(incomingConnection);
}
} catch(BindException e) {
System.out.println("포트에 바인딩할 수 없습니다. " + listeningPort);
} catch(IOException e) {
System.out.println("포트에서 ServerSocket을 인스턴스화할 수 없습니다: " + listeningPort);
}
}
유일한 변경 사항은 작동 메커니즘이 하나 더 있다는 것입니다. 백로그 값을 5로 지정하고 서버에 대한 연결을 요청하는 클라이언트가 5개 있다고 가정합니다. 우리 서버는 첫 번째 연결 처리를 시작하지만 해당 연결을 처리하는 데 오랜 시간이 걸립니다. 보류 값이 5이므로 한 번에 5개의 요청을 대기열에 넣을 수 있습니다. 우리는 하나를 작업 중이므로 다른 5개가 기다리고 있음을 의미합니다. 총 6개가 대기 중이며 처리 중입니다. 우리 서버가 여전히 1번 연결을 수락하는 중일 때(대기열에 2~6번 연결이 있다는 것을 기억하세요) 일곱 번째 클라이언트가 연결 요청을 하면 일곱 번째 클라이언트는 거부됩니다
다음을 보세요 다음 변경 사항은 분명히 모니터링되는 스레드를 처리하는 handlerConnection 메서드에 있습니다. 앞서 언급한 것처럼 멀티 스레드 버전에서는 연결 요청을 감지하면 즉시 스레드를 생성한 다음 이를 무시합니다. 다음은 문장입니다. 새 스레드를 생성합니다.
public void handlerConnection(Socket ConnectionToHandle) {
new Thread(new ConnectionHandler(connectionToHandle)).start();
}
우리는 다음을 발견했습니다. 새로운 클래스 ConnectionHandler가 있습니다. 이 클래스는 인터페이스 클래스인 Runnable입니다(이것은 인터페이스를 사용하여 구현된 스레드입니다. 이해가 되지 않으면 17번(스레드에 관한 내용)을 살펴보세요. ConnectionHandler를 사용하여 새 스레드를 생성하고 시작합니다. 방금 말했듯이 RemoteFileServer의 handlerConnection에 있는 코드는 이 인터페이스 클래스인 ConnectionHandler의 run() 메소드에 그대로 전달되었습니다.
그러면 전체 ConnectionHandler 클래스를 살펴보겠습니다.
클래스 ConnectionHandler는 Runnable을 구현합니다. {
protected Socket 소켓ToHandle;
public ConnectionHandler(Socket aSocketToHandle) {
socketToHandle = aSocketToHandle;//생성자를 통해 처리할 소켓 인스턴스를 전달합니다. 매개변수 들어오세요
}
public void run() {//소켓 읽기/쓰기를 위한 원본 코드는 모두 여기에 있습니다
try {
PrintWriter streamWriter = new PrintWriter(socketToHandle.getOutputStream());
BufferedReader streamReader = new BufferedReader(new InputStreamReader(socketToHandle.getInputStream()));
String fileToRead = streamReader.readLine();
BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead)) ;
문자열 라인 = null;
while ((line = fileReader.readLine()) != null)
streamWriter.println(line);
fileReader.close( );
streamWriter.close();
streamReader.close();
} catch(예외 e) {
System.out.println("클라이언트 처리 오류: " + e);
}
}
}
ConnectionHandler의 run() 메서드가 수행하는 작업은 RemoteFileServer의 handlerConnection()이 수행하는 작업과 같습니다. 먼저, (소켓의 getOutputStream() 및 getInputStream()을 사용하여) InputStream 및 OutputStream을 각각 BufferedReader 및 PrintWriter로 래핑합니다. 그런 다음 이 코드를 사용하여 대상 파일을 한 줄씩 읽습니다. 파일 경로는 InputStream에 로드되므로 FileReader 스트림을 사용하여 파일 경로를 중간에 래핑한 다음 BufferedReader 패키지를 통해 읽어야 합니다.
멀티스레딩 서버 연구가 완료되었습니다. 다시 한번 서버의 "멀티스레드 버전"을 생성하고 사용하는 단계를 검토해 보겠습니다.
1. 기본값 50(또는 1보다 큰 숫자 지정)을 사용하여 ServerSocket을 인스턴스화합니다.
2. ConnectionHandler 인스턴스를 사용하여 새 스레드를 생성하도록 ServerSocket의 handlerConnection()을 수정합니다.
3. RemoteFileServer의 handlerConnection() 메서드 코드를 빌려 ConnectionHandler 클래스의 run() 함수를 구현합니다.
위 내용은 Java 초보자를 위한 메모(6) 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!