版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013857458/article/details/82386244
Java Socket示例
ServerSocket
public class BioServer {
private int port;
private ExecutorService service = Executors.newFixedThreadPool(3);
public BioServer(int port) {
this.port = port;
}
public void start() {
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(port);
while (true) {
socket = serverSocket.accept();
service.submit(new ServerHandler(socket));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader reader = null;
PrintWriter writer = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
String threadName = Thread.currentThread().getName();
String requestName = socket.getInetAddress().getHostName();
String readerInfo = null;
while (true) {
readerInfo = reader.readLine();
if (readerInfo == null) {
break;
}
System.out.println("接收到客户端消息:" + readerInfo + ",处理线程:" + threadName);
writer.println(requestName + " 你的请求已处理,处理线程:" + threadName);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new BioServer(8080).start();
}
}
Socket Client
public class BioClient {
private static final String host = "127.0.0.1";
private static final int port = 8080;
public void connect(String host, int port) {
Socket socket = null;
BufferedReader reader = null;
PrintWriter writer = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
while (true) {
writer.println("Hello Server, I am " + socket.getInetAddress());
String response = reader.readLine();
System.out.println("server return message : " + response);
Thread.sleep(3000);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args){
new BioClient().connect(host, port);
}
}
源码解析
Java Socket实现类继承关系,ServerSocket,Socket中都包含一个SocketImpl对象,SocketImpl中包含一个ServerSocket和一个Socket对象,默认SocksSocketImpl
Java API调用Socket绑定端口、监听、连接等都需要调用底层系统的Socket,这些操作在DualStackPlainSocketImpl中实现
void socketCreate(boolean stream) throws IOException {
……
int newfd = socket0(stream, false /*v6 Only*/);
fdAccess.set(fd, newfd);
}
void socketConnect(InetAddress address, int port, int timeout)
throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
int connectResult;
if (timeout <= 0) {
connectResult = connect0(nativefd, address, port);
} else {
configureBlocking(nativefd, false);
try {
connectResult = connect0(nativefd, address, port);
if (connectResult == WOULDBLOCK) {
waitForConnect(nativefd, timeout);
}
} finally {
configureBlocking(nativefd, true);
}
}
/*
* We need to set the local port field. If bind was called
* previous to the connect (by the client) then localport field
* will already be set.
*/
if (localport == 0)
localport = localPort0(nativefd);
}
void socketBind(InetAddress address, int port) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
bind0(nativefd, address, port, exclusiveBind);
if (port == 0) {
localport = localPort0(nativefd);
} else {
localport = port;
}
this.address = address;
}
void socketListen(int backlog) throws IOException {
int nativefd = checkAndReturnNativeFD();
listen0(nativefd, backlog);
}
void socketAccept(SocketImpl s) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (s == null)
throw new NullPointerException("socket is null");
int newfd = -1;
InetSocketAddress[] isaa = new InetSocketAddress[1];
if (timeout <= 0) {
newfd = accept0(nativefd, isaa);
} else {
configureBlocking(nativefd, false);
try {
waitForNewConnection(nativefd, timeout);
newfd = accept0(nativefd, isaa);
if (newfd != -1) {
configureBlocking(newfd, true);
}
} finally {
configureBlocking(nativefd, true);
}
}
/* Update (SocketImpl)s' fd */
fdAccess.set(s.fd, newfd);
/* Update socketImpls remote port, address and localport */
InetSocketAddress isa = isaa[0];
s.port = isa.getPort();
s.address = isa.getAddress();
s.localport = localport;
}
1. 实例化ServerSocket
ServerSocket(int port, int backlog, InetAddress bindAddr)
- port:端口
- backlog:ServerSocket有一个队列,存放还没有来得及处理的客户端Socket,这个队列的容量就是backlog的含义,默认是50
- bindAddr:绑定地址
- FileDescriptor
一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元数据到文件本身的映射。简单的讲,也就是有了Map结构,key是fd,value是文件的信息(包括物理地址、读取模式。。。。。)
0 标准输入(stdin),1标准输出(stdout),2标准错误(stderr)
ServerSocket
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
setImpl();
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException(
"Port value out of range: " + port);
if (backlog < 1)
backlog = 50;
try {
bind(new InetSocketAddress(bindAddr, port), backlog);
} catch(SecurityException e) {
close();
throw e;
} catch(IOException e) {
close();
throw e;
}
}
//ServerSocket中有一个属性 private SocketImpl impl;
//抽象类SocketImpl中有一个Socket和ServerSocket
//父类PlainSocketImpl类中有个private AbstractPlainSocketImpl impl;真正调用Native系统socket0的实现
private void setImpl() {
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
} else {
//先执行父类PlainSocketImpl构造方法,设置impl = new DualStackPlainSocketImpl(exclusiveBind);
impl = new SocksSocketImpl();
}
if (impl != null)
impl.setServerSocket(this);
}
PlainSocketImpl(FileDescriptor fd) {
if (useDualStackImpl) {
impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
} else {
impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
}
}
//绑定端口
public void bind(SocketAddress endpoint, int backlog) throws IOException {
……
if (backlog < 1)
backlog = 50;
try {
……
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
bound = true;
}
……
}
SocketImpl getImpl() throws SocketException {
if (!created)
createImpl();
return impl;
}
void createImpl() throws SocketException {
if (impl == null)
setImpl();
try {
//真正调用系统Socket的地方
impl.create(true);
created = true;
} catch (IOException e) {
throw new SocketException(e.getMessage());
}
}
SocksSocketImpl
protected synchronized void create(boolean stream) throws IOException {
//抽象类中实现
impl.create(stream);
// set fd to delegate's fd to be compatible with older releases
this.fd = impl.fd;
}
//抽象类AbstractPlainSocketImpl
protected synchronized void create(boolean stream) throws IOException {
……
fd = new FileDescriptor();
socketCreate(true);
……
}
DualStackPlainSocketImpl
void socketCreate(boolean stream) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
int newfd = socket0(stream, false /*v6 Only*/);
fdAccess.set(fd, newfd);
}
void socketBind(InetAddress address, int port) throws IOException {
……
bind0(nativefd, address, port, exclusiveBind);
……
}
void socketListen(int backlog) throws IOException {
int nativefd = checkAndReturnNativeFD();
listen0(nativefd, backlog);
}
ServerSocket接受连接accept方法
public Socket accept() throws IOException {
……
//构造参数为null,构造方法中不执行任何操作
Socket s = new Socket((SocketImpl) null);
implAccept(s);
return s;
}
protected final void implAccept(Socket s) throws IOException {
SocketImpl si = null;
try {
if (s.impl == null)
//调用Socket中的setImpl方法设置SocketImpl实现,操作和ServerSocket一致
s.setImpl();
else {
s.impl.reset();
}
si = s.impl;
s.impl = null;
si.address = new InetAddress();
si.fd = new FileDescriptor();
//获取Socket实现,并调用accept方法,在父类PlainSocketImpl中委托给抽象类AbstractPlainSocketImpl中的impl实现,真正实现在DualStackPlainSocketImpl的方法socketAccept(SocketImpl s)中
getImpl().accept(si);
……
s.impl = si;
s.postAccept();
}