바이오, 즉 IO를 차단합니다. 소켓 기반 메시지 통신 프로세스 중에 소켓 서버는 외부에 서비스를 제공하고 소켓 클라이언트는 소켓 서버에 대한 연결을 설정 한 다음 요청 데이터를 보내고 소켓 서버가 처리 될 때까지 대기하고 처리 결과 (응답)를 반환 할 수 있습니다.
바이오 통신을 기반으로 소켓 서버가 차단됩니다. 이 모드에서 소켓 서버의 처리 기능이 매우 제한적이며 클라이언트는 서버가 유휴 상태가 될 때까지 기다릴 수 있고 요청을 처리 할 수 있음을 알 수 있습니다.
바이오 커뮤니케이션 구현
다음은 소켓 클라이언트와 통신하는 간단한 소켓 서버의 논리를 구현하기위한 바이오 모델을 기반으로 하며이 통신 방법에 대한 지각 적 이해를 갖습니다. 특정 논리는 다음과 같이 설명됩니다.
1. 소켓 클라이언트는 소켓 서버에 연결하여 "I am the Client N.";
2. 소켓 서버는 서비스 포트에 듣고 클라이언트 요청 데이터를 수신합니다. 요청 데이터가 "I Am Client"로 시작하면 클라이언트에 응답합니다. "저는 서버이며 귀하는 Nth 클라이언트입니다.";
소켓 서버 구현은 다음과 같습니다.
패키지 org.shirdrn.java.communications.bio; import java.io.ioexception; import java.io.inputstream; import java.io.outputStream; import java.net.serversocket; import java.net.socket; / *** Bio의 소켓 서버 기반* @author shieldrn*/ public class simplebiotcpserver 스레드 {/ ** 서비스 포트 번호*/ private int port = 8888; / ** 클라이언트 시퀀스 = 0에 번호*/ 개인 정적 int 할당; public simplebiotcpserver (int port) {this.port = port; } @override public void run () {Socket Socket = null; {serversocket serversocket = new Serversocket (this.port); while (true) {socket = serversocket.accept (); //이를 듣습니다. handleMessage (소켓); // handlemessage (소켓); // 연결된 클라이언트를 처리}} catch (ioException e) {e.printstacktrace (); }} / ** * 클라이언트 소켓 연결 처리 * @Param 소켓 클라이언트 소켓 * @Throws IOException * / private void handleMessage (Socket Socket) IoException {inputStream in = socket.getInputStream (); // stream : client-> server (읽기) outputStream out = socket.getOutputStream (); // stream : server-> client (쓰기) int lecceBytes; 바이트 [] 수신 버퍼 = 새로운 바이트 [128]; 문자열 clientMessage = ""; if ((lecceBytes = in.Read (lecceBuffer))! = -1) {clientMessage = new String (lecceBuffer, 0, lecceBytes); if (clientMessage.StartSwith ( "I Am Client"))) {String ServerResponsewords = "나는 서버이며" + (++ 시퀀스) + "th client"; out.write (serverResponsewords.getBytes ()); }} out.flush (); System.out.println ( "서버 : ClientMessage->" + ClientMessage를 수신); } public static void main (String [] args) {SimpleBiotCpserver Server = New SimpleBiotCpserver (1983); server.start (); }} 위의 구현은 복잡한 예외 처리를 수행하지 않습니다.
소켓 클라이언트 구현은 다음과 같습니다.
패키지 org.shirdrn.java.communications.bio; import java.io.ioexception; import java.io.inputstream; import java.io.outputStream; import java.net.socket; import java.net.unknownhostexception; import java.util.date; / ** * bio * @author shieldrn */ public class simplebiotcpclient {private String iPaddress; 개인 int 포트; 개인 정적 int pos = 0; public simplebiotcpclient () {} public simplebiotcpclient (String iPaddress, int port) {this.ipaddress = iPaddress; this.port = 포트; } / *** 소켓 서버에 연결하고 요청 데이터 보내기 데이터* @param 데이터 요청 데이터* / public void send (byte [] data) {Socket Socket = null; outputStream out = null; inputStream in = null; try {socket = new Socket (this.ipaddress, this.port); // connect // 요청을 보내십시오. out.write (데이터); out.flush (); // 응답을 받기 = socket.getInputStream (); int totalbytes = 0; int 수신기 = 0; 바이트 [] 수신 버퍼 = 새로운 바이트 [128]; if ((lecceBytes = in.Read (lecceBuffer))! = -1) {TotalBytes += 수신기; } string serverMessage = 새 문자열 (lecceBuffer, 0, wearchBytes); System.out.println ( "클라이언트 : ServerMessage->" + ServerMessage 수신); } catch (unknownHostException e) {e.printstacktrace (); } catch (ioexception e) {e.printstacktrace (); } catch (예외 e) {e.printstacktrace (); } 마침내 {try {// 요청을 보내고 응답을 받고 통신이 완료되고 연결을 닫습니다 .Close (); 넣다(); socket.close (); } catch (ioexception e) {e.printstacktrace (); }}} public static void main (String [] args) {int n = 1; StringBuffer data = new StringBuffer (); 날짜 시작 = 새 날짜 (); for (int i = 0; i <n; i ++) {data.delete (0, data.length ()); data.append ( "I am the Client") .Append (++ pos) .append ( "."); SimpleBiotCpClient Client = New SimpleBiotCpclient ( "LocalHost", 1983); client.send (data.toString (). getBytes ()); } 날짜 종료 = 새 날짜 (); 긴 비용 = end.gettime () - start.gettime (); System.out.println (n + "요청 비용" + cost + "ms."); }} 먼저 소켓 서버 프로세스 SimpleBiotCpserver를 시작한 다음 소켓 클라이언트 SimpleBiotCpclient를 실행하십시오. 서버가 요청 데이터를 수신 한 다음 클라이언트에 응답하고 클라이언트가 서버에서 응답 데이터를 수신한다는 것을 알 수 있습니다.
위의 구현에서는 소켓 클라이언트와 서버가 모두 작성되고 읽습니다. 실제로, 각 통신 중에 데이터의 양이 특히 크면 서버는이를 수락 할 수 없습니다. 클라이언트가 요청한 데이터 바이트 수를 결정할 때 읽고 처리 할 수 있습니다.
또한 위에서 언급 한 스트림이 포장되지 않으면 실제로 버퍼 할 수없는 등의 성능 손실이 발생합니다.
데이터를 수신하는 소켓 서버의 경우 다중 루프에서 읽은 바이트 데이터를 가변 길이 바이트 버퍼를 통해 저장할 수있는 것이 훨씬 편리합니다. 그러나 예를 들어 BytearRayoutputStream을 사용합니다.
bytearrayoutputStream data = new BytearRayoutputStream (); data.write (수신자, TotalBytes, TotalBytes + wickByBytes);
바이오 커뮤니케이션 테스트
다음은 많은 요청이있는 시나리오에서 소켓 서버 처리의 효율성을 테스트합니다.
첫 번째 방법 : for 루프를 통해 5000 개의 소켓 클라이언트를 시작하고 요청을 보냅니다. 코드는 다음과 같습니다.
public static void main (String [] args) {int n = 5000; StringBuffer data = new StringBuffer (); 날짜 시작 = 새 날짜 (); for (int i = 0; i <n; i ++) {data.delete (0, data.length ()); data.append ( "I am the Client") .Append (++ pos) .append ( "."); SimpleBiotCpClient Client = New SimpleBiotCpclient ( "LocalHost", 1983); client.send (data.toString (). getBytes ()); } 날짜 종료 = 새 날짜 (); 긴 비용 = end.gettime () - start.gettime (); System.out.println (n + "요청 비용" + cost + "ms."); } 테스트 후 약 9864ms가 필요합니다.
두 번째 방법 : 5,000 개의 독립 클라이언트 스레드를 시작하고 동시에 요청하면 서버가 중요합니다.
패키지 org.shirdrn.java.communications.bio; import java.io.ioexception; import java.io.inputstream; import java.io.outputStream; import java.net.serversocket; import java.net.socket; import java.net.unknownhostexception; import java.util.date; / ** * 바이오를 기반으로 한 소켓 통신 테스트 * * @author shieldrn */ public class simplebiotcptest {static int stroodcount = 5000; / *** bio* @author shieldrn*/ static class socketserver를 기반으로 한 소켓 서버 프로세스 스레드 {/ ** 서비스 포트 번호*/ private int port = 8888; / ** 클라이언트에 숫자를 할당*/ private static int sequence = 0; public socketserver (int port) {this.port = port; } @override public void run () {Socket Socket = null; int 카운터 = 0; {serversocket serversocket = new Serversocket (this.port); 부울 플래그 = 거짓; 날짜 시작 = null; while (true) {socket = serversocket.accept (); // 청취 // 시간이 시작 if (! flag) {start = new Date (); flag = true; } this.handleMessage (소켓); // 연결된 클라이언트 요청을 처리합니다. if (++ counter == ThreadCount) {date end = new Date (); long last = end.gettime () - start.gettime (); System.out.println (ThreadCount + "요청 비용" + last + "ms."); }}}} catch (ioexception e) {e.printstacktrace (); }} / ** * 클라이언트 소켓 연결 처리 * @Param 소켓 클라이언트 소켓 * @Throws IOException * / private void handleMessage (Socket Socket) IoException {inputStream in = socket.getInputStream (); // stream : client-> server (읽기) outputStream out = socket.getOutputStream (); // stream : server-> client (쓰기) int lecceBytes; 바이트 [] 수신 버퍼 = 새로운 바이트 [128]; 문자열 clientMessage = ""; if ((lecceBytes = in.Read (lecceBuffer))! = -1) {clientMessage = new String (lecceBuffer, 0, lecceBytes); if (clientMessage.StartSwith ( "I Am Client"))) {String ServerResponsewords = "나는 서버이며" + (++ 시퀀스) + "th client"; out.write (serverResponsewords.getBytes ()); }} out.flush (); System.out.println ( "서버 : ClientMessage->" + ClientMessage를 수신); }} / ** * bio * @author shieldrn * / static class socketclient emplements runnable {private String iPaddress; 개인 int 포트; / ** 보내기 요청*/ 개인 문자열 데이터; public socketclient (String iPaddress, int port) {this.ipaddress = iPaddress; this.port = 포트; } @override public void run () {this.send (); } / *** 소켓 서버에 연결하고 요청 보내기 데이터* / public void send () {Socket Socket = null; outputStream out = null; inputStream in = null; try {socket = new Socket (this.ipaddress, this.port); // connect // 요청을 보내십시오. out.write (data.getBytes ()); out.flush (); // 응답을 받기 = socket.getInputStream (); int totalbytes = 0; int 수신기 = 0; 바이트 [] 수신 버퍼 = 새로운 바이트 [128]; if ((lecceBytes = in.Read (lecceBuffer))! = -1) {TotalBytes += 수신기; } string serverMessage = 새 문자열 (lecceBuffer, 0, wearchBytes); System.out.println ( "클라이언트 : ServerMessage->" + ServerMessage 수신); } catch (unknownHostException e) {e.printstacktrace (); } catch (ioexception e) {e.printstacktrace (); } catch (예외 e) {e.printstacktrace (); } 마침내 {try {// 요청을 보내고 응답을 받고 통신이 완료되고 연결을 닫습니다 .Close (); 넣다(); socket.close (); } catch (ioexception e) {e.printstacktrace (); }}} public void setData (문자열 데이터) {this.data = data; }} public static void main (string [] args)은 예외 {socketserver server = new SocketServer (1983); server.start (); Thread.sleep (3000); for (int i = 0; i <ThreadCount; i ++) {SocketClient Client = New SocketClient ( "LocalHost", 1983); client.setData ( "나는 클라이언트" + (i + 1) + "); 새 스레드 (클라이언트) .start (); Thread.sleep (0, 1); }}}테스트 후 약 7110ms (약 7 초)가 걸리며 크게 개선되지 않습니다.
바이오 커뮤니케이션 개선
위의 테스트를 통해 소켓 서버가 클라이언트의 요청을 처리하면 차단이 발생하여 요청의 동시 처리 효율에 심각한 영향을 미칩니다. 실제로, 소켓 서버의 연결 기능 범위 내에서 수신 된 요청은 독립적 일 수 있으므로 하나의 요청과 하나의 스레드로 요청을 처리하여 위의 문제를 해결할 수 있습니다. 이러한 방식으로 서버 측에는 클라이언트의 여러 요청에 해당하는 여러 처리 스레드가 있으며 처리 효율이 어느 정도 개선되었습니다.
아래에서 단일 스레드를 통해 요청을받은 다음 스레드 풀을 위임하여 다중 스레드 동시 처리 요청을 수행하십시오.
/ *** bio* @author shieldrn*/ static class socketserver를 기반으로 한 소켓 서버 프로세스 스레드 {/ ** 서비스 포트 번호*/ private int port = 8888; / ** 클라이언트에 번호 할당*/ private static int sequence = 0; / ** 클라이언트를 처리하기위한 스레드 풀*/ private executorService 풀; public socketserver (int port, int poolsize) {this.port = 포트; this.pool = executors.newfixedthreadpool (poolsize); } @override public void run () {Socket Socket = null; int 카운터 = 0; {serversocket serversocket = new Serversocket (this.port); 부울 플래그 = 거짓; 날짜 시작 = null; while (true) {socket = serversocket.accept (); // 청취 // 요청이 (! flag) {start = new Date (); flag = true; } // 클라이언트 요청을 스레드 풀에 넣어 풀을 프로세스 풀 (new requestHandler (socket)); if (++ counter == ThreadCount) {date end = new Date (); long last = end.gettime () - start.gettime (); System.out.println (ThreadCount + "요청 비용" + last + "ms."); }}} catch (ioexception e) {e.printstacktrace (); }} / ** * 클라이언트 요청 처리 스레드 클래스 * * @Author Shieldrn * / 클래스 요청 핸들러는 실행 가능 {개인 소켓 소켓; Public RequestAndler (소켓 소켓) {this.socket = 소켓; } @override public void run () {try {inputStream in = socket.getInputStream (); // stream : client-> server (읽기) outputStream out = socket.getOutputStream (); // stream : server-> client (쓰기) int lecceBytes; 바이트 [] 수신 버퍼 = 새로운 바이트 [128]; 문자열 clientMessage = ""; if ((lecceBytes = in.Read (lecceBuffer))! = -1) {clientMessage = new String (lecceBuffer, 0, lecceBytes); if (clientMessage.StartSwith ( "I Am Client"))) {String ServerResponsewords = "나는 서버이며" + (++ 시퀀스) + "th client"; out.write (serverResponsewords.getBytes ()); }} out.flush (); System.out.println ( "서버 : ClientMessage->" + ClientMessage를 수신); } catch (ioexception e) {e.printstacktrace (); }}}}}}}}}}이 개선 된 방법은 서버 처리 요청의 동시성을 향상 시킨다는 것을 알 수 있지만 각 요청은 스레드에 의해 처리되어야합니다. 많은 요청으로 인해 서버가 처리를 위해 많은 수의 프로세스를 시작하게되며, 이는 비교적 서버 리소스를 차지합니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.