Java가 NIO 패키지를 사용하여 Socket 통신을 구현하는 인스턴스 코드
java.nio 패키지는 I/O 작업의 효율성을 높이기 위해 Java가 1.4 이후에 추가되었습니다.nio 패키지에는 다음과 같은 클래스 또는 인터페이스가 포함됩니다.
일단 보조 클래스 몇 개 소개해드릴게요.
보조 클래스 Serializable Util, 이 클래스는 자바 대상을 바이트 그룹으로 서열화하거나 바이트 그룹을 자바 대상으로 반서열화하는 데 사용됩니다.
package com.googlecode.garbagecan.test.socket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializableUtil {
public static byte[] toBytes(Object object) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch(IOException ex) {
throw new RuntimeException(ex.getMessage(), ex);
} finally {
try {
oos.close();
} catch (Exception e) {}
}
}
public static Object toObject(byte[] bytes) {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bais);
Object object = ois.readObject();
return object;
} catch(IOException ex) {
throw new RuntimeException(ex.getMessage(), ex);
} catch(ClassNotFoundException ex) {
throw new RuntimeException(ex.getMessage(), ex);
} finally {
try {
ois.close();
} catch (Exception e) {}
}
}
}
보조 클래스 My Request Object와 My Response Object, 이 두 클래스는 일반적인java 대상으로 Serializable 인터페이스를 실현했다.MyRequestObject 클래스는 클라이언트가 보낸 요청이고 MyResponseObject는 서버 측에서 응답한 것입니다.
package com.googlecode.garbagecan.test.socket.nio;
import java.io.Serializable;
public class MyRequestObject implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String value;
private byte[] bytes;
public MyRequestObject(String name, String value) {
this.name = name;
this.value = value;
this.bytes = new byte[1024];
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Request [name: " + name + ", value: " + value + ", bytes: " + bytes.length+ "]");
return sb.toString();
}
}
package com.googlecode.garbagecan.test.socket.nio;
import java.io.Serializable;
public class MyResponseObject implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String value;
private byte[] bytes;
public MyResponseObject(String name, String value) {
this.name = name;
this.value = value;
this.bytes = new byte[1024];
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Response [name: " + name + ", value: " + value + ", bytes: " + bytes.length+ "]");
return sb.toString();
}
}
다음은 주로 서버 측의 코드를 살펴보겠습니다. 그 중에서 일부 영문 주석은 코드를 이해하는 데 도움이 됩니다. 주석은 주로 jdk의 문서와 예입니다. 여기는 재번역이 없습니다.
package com.googlecode.garbagecan.test.socket.nio;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.googlecode.garbagecan.test.socket.SerializableUtil;
public class MyServer3 {
private final static Logger logger = Logger.getLogger(MyServer3.class.getName());
public static void main(String[] args) {
Selector selector = null;
ServerSocketChannel serverSocketChannel = null;
try {
// Selector for incoming time requests
selector = Selector.open();
// Create a new server socket and set to non blocking mode
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
// Bind the server socket to the local host and port
serverSocketChannel.socket().setReuseAddress(true);
serverSocketChannel.socket().bind(new InetSocketAddress(10000));
// Register accepts on the server socket with the selector. This
// step tells the selector that the socket wants to be put on the
// ready list when accept operations occur, so allowing multiplexed
// non-blocking I/O to take place.
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// Here's where everything happens. The select method will
// return when any operations registered above have occurred, the
// thread has been interrupted, etc.
while (selector.select() > 0) {
// Someone is ready for I/O, get the ready keys
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
// Walk through the ready keys collection and process date requests.
while (it.hasNext()) {
SelectionKey readyKey = it.next();
it.remove();
// The key indexes into the selector so you
// can retrieve the socket that's ready for I/O
execute((ServerSocketChannel) readyKey.channel());
}
}
} catch (ClosedChannelException ex) {
logger.log(Level.SEVERE, null, ex);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
} finally {
try {
selector.close();
} catch(Exception ex) {}
try {
serverSocketChannel.close();
} catch(Exception ex) {}
}
}
private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {
SocketChannel socketChannel = null;
try {
socketChannel = serverSocketChannel.accept();
MyRequestObject myRequestObject = receiveData(socketChannel);
logger.log(Level.INFO, myRequestObject.toString());
MyResponseObject myResponseObject = new MyResponseObject(
"response for " + myRequestObject.getName(),
"response for " + myRequestObject.getValue());
sendData(socketChannel, myResponseObject);
logger.log(Level.INFO, myResponseObject.toString());
} finally {
try {
socketChannel.close();
} catch(Exception ex) {}
}
}
private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {
MyRequestObject myRequestObject = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
byte[] bytes;
int size = 0;
while ((size = socketChannel.read(buffer)) >= 0) {
buffer.flip();
bytes = new byte[size];
buffer.get(bytes);
baos.write(bytes);
buffer.clear();
}
bytes = baos.toByteArray();
Object obj = SerializableUtil.toObject(bytes);
myRequestObject = (MyRequestObject)obj;
} finally {
try {
baos.close();
} catch(Exception ex) {}
}
return myRequestObject;
}
private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {
byte[] bytes = SerializableUtil.toBytes(myResponseObject);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
socketChannel.write(buffer);
}
}
다음은 클라이언트의 코드입니다. 코드가 비교적 간단합니다. 100개의 라인을 시작하여 서버에 접근하는 것입니다.
package com.googlecode.garbagecan.test.socket.nio;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.googlecode.garbagecan.test.socket.SerializableUtil;
public class MyClient3 {
private final static Logger logger = Logger.getLogger(MyClient3.class.getName());
public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
final int idx = i;
new Thread(new MyRunnable(idx)).start();
}
}
private static final class MyRunnable implements Runnable {
private final int idx;
private MyRunnable(int idx) {
this.idx = idx;
}
public void run() {
SocketChannel socketChannel = null;
try {
socketChannel = SocketChannel.open();
SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
socketChannel.connect(socketAddress);
MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);
logger.log(Level.INFO, myRequestObject.toString());
sendData(socketChannel, myRequestObject);
MyResponseObject myResponseObject = receiveData(socketChannel);
logger.log(Level.INFO, myResponseObject.toString());
} catch (Exception ex) {
logger.log(Level.SEVERE, null, ex);
} finally {
try {
socketChannel.close();
} catch(Exception ex) {}
}
}
private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {
byte[] bytes = SerializableUtil.toBytes(myRequestObject);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
socketChannel.write(buffer);
socketChannel.socket().shutdownOutput();
}
private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {
MyResponseObject myResponseObject = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
byte[] bytes;
int count = 0;
while ((count = socketChannel.read(buffer)) >= 0) {
buffer.flip();
bytes = new byte[count];
buffer.get(bytes);
baos.write(bytes);
buffer.clear();
}
bytes = baos.toByteArray();
Object obj = SerializableUtil.toObject(bytes);
myResponseObject = (MyResponseObject) obj;
socketChannel.socket().shutdownInput();
} finally {
try {
baos.close();
} catch(Exception ex) {}
}
return myResponseObject;
}
}
}
마지막으로 위의 코드를 테스트합니다. 먼저 서버 클래스를 실행하고 클라이언트 클래스를 실행하면 서버 사이드와 클라이언트 사이드 컨트롤러에서 보내거나 받은 My Request Object 또는 My Response Object 대상을 볼 수 있습니다.이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
38. Java의 Leetcode 솔루션텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.