封裝socket的通信協議完成文本通信
socket是典型的cs架構,由於client端通過OutputStream發送消息,server端通過InputStream接收消息。一般發送本文信息都是一條條發出去的,接收端無法得知每條消息的邊界。所以對協議封裝一下完成文本信息逐條發送並在服務端實時解析。
首先約定好協議的標準
public class Protocol {
public static final int OPEN = 1;
public static final int TALK = 2;
public static final int QUIT = 3;
}
socket客戶端的代碼
public class EchoClient implements Closeable {
private String host;
private int port;
private Socket client;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
try {
client = new Socket(host, port);
open(client);
} catch (IOException e) {
e.printStackTrace();
}
}
private void open(Socket client) {
try {
OutputStream outputStream = client.getOutputStream();
DataOutputStream write = new DataOutputStream(outputStream);
write.write(Protocol.OPEN);
write.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String message) {
try {
byte[] data = message.getBytes("UTF-8");
OutputStream outputStream = client.getOutputStream();
DataOutputStream write = new DataOutputStream(outputStream);
write.writeByte(Protocol.TALK);
write.writeInt(data.length);
write.write(data);
write.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void close() throws IOException {
OutputStream outputStream = null;
try {
outputStream = client.getOutputStream();
DataOutputStream write = new DataOutputStream(outputStream);
write.write(Protocol.QUIT);
write.flush();
write.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
client.close();
}
public static void main(String[] args) {
try (EchoClient client = new EchoClient("localhost", 55533)) {
for (int i = 0; i < 5000; i++) {
client.sendMessage(String.format("hello world %s", i));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
socket服務端的代碼
public class EchoServer implements Closeable, Runnable {
private int port;
private ServerSocket server;
private boolean RUNNINGSTATE = false;
public EchoServer(int port) {
this.port = port;
try {
server = new ServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
}
public void listener() {
Socket client = null;
try {
client = server.accept();
} catch (IOException e) {
e.printStackTrace();
}
accept(client);
}
@Override
public void run() {
listener();
}
public void onOpen(Socket socket) {
RUNNINGSTATE = true;
System.out.println(String.format("新連接%s進來了", socket.getInetAddress()));
}
public void onClose(Socket socket) {
System.out.println(String.format("客戶端%s退出連接", socket.getInetAddress()));
}
public void handle(String message) {
System.out.println(message);
}
public void accept(Socket socket) {
try {
InputStream inputStream = socket.getInputStream();
BufferedInputStream read = new BufferedInputStream(inputStream);
int type = 0;
while ((type = read.read()) != -1) {
switch (type) {
case Protocol.OPEN:
onOpen(socket);
break;
case Protocol.QUIT:
onClose(socket);
break;
case Protocol.TALK:
byte[] buffer = new byte[1024];
int len = readInt(read);
int offset = 0;
StringBuilder sb = new StringBuilder();
while (len > 0 && (offset = read.read(buffer, 0, len < buffer.length ? len : buffer.length)) != -1) {
sb.append(new String(buffer, 0, offset, "UTF-8"));
len -= offset;
}
handle(sb.toString());
}
}
read.close();
inputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public final int readInt(InputStream in) throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}
public boolean isRUNNINGSTATE() {
return RUNNINGSTATE;
}
public static void main(String[] args) {
EchoServer echoServer = new EchoServer(55533);
echoServer.run();
}
@Override
public void close() throws IOException {
server.close();
}
}
然後啓動服務端和客戶端即可完成消息的發送和接受