客户端:
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//使用socket来连接到指定服务器
while(true){
Socket s = new Socket("127.0.0.1",8888);
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//同理,下面的br.readLine()也把程序阻塞了!!
String s1 = br.readLine();
System.out.println(s1);
System.out.println("请输入返回给服务器的话:");
Scanner scanner = new Scanner(System.in);
String string = scanner.nextLine();
bw.write("来自客户端的信息:"+string);
}
}
}
服务器端:
public class Server {
public static void main(String[] args) throws IOException {
//创建一个serversocket用于监听客户端socket的连接请求
ServerSocket ss = new ServerSocket(8888);
while(true){
Socket s = ss.accept();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println("请输入要发送到客户端的信息:");
Scanner scanner = new Scanner(System.in);
String string = scanner.nextLine();
bw.write("来自服务器端的信息:"+string);
//因为readLine()方法是阻塞式的,所以这句话无论放在程序的哪里,程序都会等在那,什么也不执行!
//比如说,放在下面现在的位置,那么好,输出要发送给客户端的话之后,程序就阻塞在那里不动了,因为它在等待客户端给它传话呢!
//即使先让客户端发话也是没用的,因为客户端也在等服务端给它传话!所以也阻塞
System.out.println(br.readLine());
bw.close();
s.close();
}
}
}
上面这个小程序无法实现客户端和服务端来回对话,原因上面注释中已经说明了,就是因为br.readLine()是阻塞式的。
来看改进后的例子:
客户端:
public class MyClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket s = new Socket("127.0.0.1",30000);
new Thread(new ClientThread(s)).start();
PrintStream ps = new PrintStream(s.getOutputStream());
String line = null;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
while((line = br.readLine())!=null){
ps.println(line);
}
}
}
public class ClientThread implements Runnable{
private Socket s;
BufferedReader br = null;
public ClientThread(Socket s) throws IOException{
this.s = s;
br = new BufferedReader(new
InputStreamReader(s.getInputStream()));
}
public void run(){
try {
String content = null;
while((content = br.readLine())!=null){
System.out.println(content);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端:
public class MyServer {
public static ArrayList<Socket> socketList = new ArrayList<Socket>();
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(30000);
while(true){
Socket s = ss.accept();
socketList.add(s);
//为什么加上线程就能完成客户端和服务端通信呢?
//因为原来单线程的时候,服务端等待接收来自客户端的信息时,br=readLine()方法是阻塞式的,
//所以无论把br=readLine()放在程序哪里都会阻塞!客户端也是一个道理。
//而加上了线程就不一样了,比如下面:假设先执行了子线程new Thread(new ServerThread(s)).start(),
//然后子线程被阻塞(因为在等待客户端传话),所以主线程得到执行,同理客户端也是这个道理。总之,总能保证整个程序能执行下去
new Thread(new ServerThread(s)).start();
PrintStream ps = new PrintStream(s.getOutputStream());
String line = null;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
while((line = br.readLine())!=null){
ps.println(line);
}
}
}
}
public class ServerThread implements Runnable{
Socket s = null;
BufferedReader br = null;
public ServerThread(Socket s) throws IOException{
this.s = s;
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
@Override
public void run() {
try{
String content = null;
while((content = readFromClient()) != null){
System.out.println(content);
}
}catch (Exception e) {
e.printStackTrace();
}
}
private String readFromClient(){
try {
return br.readLine();
} catch (IOException e) {
MyServer.socketList.remove(s);
}
return null;
}
}
加上了线程就能实现对话功能了。通过这两个小例子的对比,让我更加清楚的认识到多线程的好处和必要性,并且还让我熟悉了socket通信,一举多得。