每当程序建立一个新的套接字连接,也就是说当成功调用accept的时候,将创建一个新的线程来处理服务器和该客户端之间的连接,而主程序将立即返回并等待下一个连接。
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8189);
int i=5656;
while(true){
Socket s = ss.accept();
SocketThread socketThread = new SocketThread(s,++i);
new Thread(socketThread).start();
}
}
}
class SocketThread implements Runnable{
private Socket s;
private int i;
public SocketThread(Socket s,int i) {
this.s=s;
this.i=i;
}
public void run(){
try {
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
PrintWriter pw = new PrintWriter(os);
BufferedReader bf = new BufferedReader(new InputStreamReader(is));
pw.println("hello,"+i+",enter bye to close");
pw.flush();
boolean flag=true;
String input;
while((input=bf.readLine())!=null&& flag){
pw.println(i+"==>"+input);
if(input.equals("bye")){
flag=false;
}
pw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用上面的服务器就可以使多个客户端连接。
window多个cmd中使用telnet 127.0.0.1 8189,就可以创建多个客户端。
telnet在控制面板中“程序和功能”“打开或关闭windows功能”里面,要勾选才有用。
下面的程序也行
Socket a = new Socket("127.0.0.1",8189);
InputStream is = a.getInputStream();
OutputStream os = a.getOutputStream();
PrintWriter pw = new PrintWriter(os);
BufferedReader bf = new BufferedReader(new InputStreamReader(is));
Scanner scanner = new Scanner(System.in);
String s;
while((s=bf.readLine())!=null){
System.out.println(s);
pw.println(scanner.nextLine());
pw.flush();
}
多个类一起运行也可以看出效果。
半关闭
半关闭( half-close)提供了这样一种能力:套接字连接的一端可以终止其输出,同时仍旧可以接收来自另一端的数据。
可以通过关闭一个套接字的输出流来表示发送给服务器的请求数据已经结束,但是必须保持输入流处于打开状态。
当然,该协议只适用于一站式( one-shot)的服务,例如HTTP服务,在这种服务中,客户端连接服务器,发送一个请求,捕获响应信息,然后断开连接。
void shutdownOutput() 将输出流设为“流结束”。
void shutdownInput() 将输入流设为“流结束”。
boolean isOutputShutdown() 如果输出已被关闭,则返回true。
boolean isInputShutdown() 如果输入已被关闭,则返回true。
其实就是输入流或者输出流中一个已经用完了,不会用了就把它关闭了,但是另一个流还有用,不关闭。
可中断的套接字
当连接到一个套接字时,当前线程将会被阻塞直到建立连接或产生超时为止。同样地,当通过套接字读写数据时,当前线程也会被阻塞直到操作成功或产生超时为止。
在交互式的应用中,也许会考虑为用户提供一个功能,用以取消那些看似不会成功的连接。但是,当线程因套接字长时间无法响应而发生阻塞时,
无法通过调用interrupt来解除阻塞。
为了中断套接字操作,可以使用java.nio包提供的一个特性—SocketChannel类。
SocketChannel sc =SocketChannel.open(new InetSocketAddress(hostname, port));
通道( channel)并没有与之相关联的流。实际上,它所拥有的read和write方法都是通过调用Buffer对象来实现的。 ReadableByteChannel接口和WritableByteChannel接口都声明了这两个方法。
SocketChannel sc =SocketChannel.open(new InetSocketAddress("127.0.0.1", 8189));
Scanner scanner = new Scanner(sc);
InputStream in = Channels.newInputStream(sc);
OutputStream put = Channels.newOutputStream(sc);
假设线程正在执行打开、读取或写入操作,此时如果线程发生中断,那么这些操作将不会陷入阻塞,而是以抛出异常的方式结束。InetSocketAddress(String hostname, int port)
通过主机和端口参数创建一个地址对象,并在创建过程中解析主机名。如果主机名不能被解析,那么该地址对象的unresolved属性将被设为true。
boolean isUnresolved()如果不能解析该地址对象,则返回true。