实现一个服务器为一个客户端服务
什么也别说先撸一个服务器实现以下几个步骤
- 通过输入数据从客户端接受一个命令
- 解码这个客户端命令
- 收集客户端所请求的信息
- 通过输出数据流发送信息到客户端
// 代码详情-实现单个socket服务器
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class ServerTest {
public static void main(String[] args) throws IOException{
ServerSocket s = new ServerSocket(8189);
Socket incoming = s.accept();
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
try (Scanner in = new Scanner(inStream)){
PrintWriter out = new PrintWriter(outStream,true);
out.println("hello client");
boolean done = false;
while (!done && in.hasNextLine()){
String line = in.nextLine();
out.println("Echo:" + line);
if(line.trim().equals("BYE")) done = true;
}
}
}
}
ServerSocket (int port ) 创建一个监听端口的套接字
Socket accept() 等待链接。该方法阻塞当前线程直到建立连接为止,该方法返回一个socket对象,通过此对象与连接中的客户端进行通信
void close() 关闭套接字
如何让一个服务器为多个客户端服务?
- 程序接受连接建立一个套接字连接
- 调用accept()启动一个新的线程处理server与client连接。
- 主程序循环等待连接
package socket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ThreadedEchoServer {
public static void main(String[] args) {
try {
int i =1;
ServerSocket s= new ServerSocket(8189);
while (true){
Socket incomeing = s.accept();
System.out.println("Spwaning"+ i );
Runnable r = new ThreadedEchoHandler(incomeing);
Thread t = new Thread(r);
t.start();
i++;
}
}catch (IOException error){
error.printStackTrace();
}
}
}
```ThreadedEchoHandler.java
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
class ThreadedEchoHandler implements Runnable{
private Socket incoming;
public ThreadedEchoHandler(Socket i){
incoming = i;
}
public void run() {
try {
try {
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
Scanner in = new Scanner(inStream);
PrintWriter out = new PrintWriter(outStream,true);
out.println("hello client");
boolean done = false;
while (!done && in.hasNextLine()){
String line = in.nextLine();
out.println("Echo:" + line);
if(line.trim().equals("BYE")) done = true;
}
}finally {
incoming.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
可中断套接字
当我们一个client连接一个套接字时,当前线程会被阻塞直到建立连接或者超时为止
同样的当通过套接字读写数据时,当前线程也会被阻塞或者直到超时
对于这种阻塞我们无法通过interrupt来解除阻塞
中断套接字
对于这种情况可以使用java.nio提供的一个特性----SocketChannel类
SocketChannel chananel = SocketChannel..open(new InetSocketAdress(host,port))
使用SocketChannel来打开一个通道如果线程阻塞将以抛出异常结束而不是陷入阻塞
上面提到interupt 回忆一下interupt方法
thread.interrupt(); 线程通过interupt() 把中断标志位设置为true
线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)
使用Thread.currentThread().isInterrupted()方法检测
顺便再提一下其他和线程阻塞有关方法
sleep()
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态
在调用sleep()方法的过程中,线程不会释放对象锁。
wait()
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。