一、使用Socket和ServerSocket编写简易的客户端和服务端并实现双向通信
1 使用ServerSocket建立一个服务端:
1.1 需要绑定一个未使用的端口
ServerSocket serverSocket = new ServerSocket(9999);
此时,主机会在9999端口上监听来自客户端的连接请求,操作系统会将接受到了请求放入一个先进先出的队列中,在ServerSocket的其它构造方式中有一个参数backlog,就是用来指定这个队列的大小的,默认为50。当请求数超过这个队列大小时,服务端会拒绝客户端的请求。
1.2 调用accept()方法,获取一个Socket实例,这时候服务端就和客户端之间建立的通信。
Socket socket = serverSocket.accept();
1.3 通过socket.getInputStream()获取输入流,之后可以在输入流中获取到客户端传输过来的数据
InputStream is = socket.getInputStream();
读取完毕后调用socket.shutdownInput()关闭输入
1.4 通过socket.getOutputStream()获取输出流,之后可以通过这个输出流向客户段返回数据
OutputStream os = socket.getOutputStream();
写操作完成后需要调用socket.shutdownOutput()关闭输出
1.5 关闭socket
socket.close();
1.6 关闭服务:一般会在finally块中去关闭
serverSocket.close();
下面是服务端代码:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
* @author Administrator
*
*/
public class SimpleServer {
private final static String MESSAGE = "Hello Client";
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(9999);
System.out.println("server started");
Socket socket = null;
while(true) {
//通过accept获取一个Socket实例并建立一客户段的连接
socket = serverSocket.accept();
System.out.println("read a message from stream");
//获取输入流,读取客户端传输的数据
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bt = new byte[256];
int n = -1;
//当客户端关闭其输出流时,read会返回-1
while((n = is.read(bt)) != -1) {
baos.write(bt, 0, n);
}
//关闭输入
socket.shutdownInput();
//传输字符,一般情况下必须指定字符编码
System.out.println("message:" + new String(baos.toByteArray(), "UTF-8"));
System.out.println("return a message to client");
//获取输出流,向客户端返回数据
OutputStream os = socket.getOutputStream();
os.write(MESSAGE.getBytes("UTF-8"));
//此处需要关闭输出,否则客户端的读操作将一直循环下去
socket.shutdownOutput();
//关闭socket
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(null != serverSocket) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("finished...");
}
}
}
2.使用Socket创建一个客户端,并向服务端发送请求
2.1 使用Socket建立客户端,需要指定服务器地址和端口
Socket socket = new Socket("127.0.0.1", 9999);
2.2 通过socket.getOutputStream()获取输出流,向服务端传输数据
OutputStream os = socket.getOutputStream();
写操作完成后需要调用socket.shutdownOutput()关闭输出
2.3 通过socket.getInputStream()获取输入流,并从输入流中获取服务端返回的数据
InputStream is = socket.getInputStream();
读取完毕后调用socket.shutdownInput()关闭输入
2.4 关闭socket
socket.close();
下面是客户段代码:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
*
* @author Administrator
*
*/
public class SimpleClient {
private final static String MESSAGE = "hello server";
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
InputStream is = null;
try {
socket = new Socket("127.0.0.1", 9999);
System.out.println("successed to connect to server");
System.out.println("send a message to server");
//获取输出流,向服务端发送数据
os = socket.getOutputStream();
//传输字符,一般情况下必须指定字符编码
os.write(MESSAGE.getBytes("UTF-8"));
//此处需要关闭输出,否则服务端的读操作将一直循环下去
socket.shutdownOutput();
System.out.println("read a message from stream");
is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bt = new byte[256];
int n = -1;
//当客户端关闭其输出流时,read会返回-1
while((n = is.read(bt)) != -1) {
baos.write(bt, 0, n);
}
System.out.println("message:" + new String(baos.toByteArray(), "UTF-8"));
//关闭输入
socket.shutdownInput();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(null != socket) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("finished...");
}
}
}
这样一个简单的并能实现双向通信的客户端和服务端就完成了。
在上面的这里实例中,服务端通过一个while循环来处理客户段发送的请求,但是在实际中,服务段处理请求可能会需要一定的时间,这样在前一个请求未处理完成时,服务端无法处理其它的请求,因此可以通过配置一个线程池来对每次调用accept获取的Socket生成一个线程来处理请求。
注:在运行代码时,必须先启动服务端代码,否则启动客户端会找不到对应的服务端而抛出java.net.ConnectException: Connection refused: connect的异常。