import java.io.*; import java.net.*; public class MyServer { public static void main(String[] args) throws IOException{ ServerSocket server=new ServerSocket(5678); //侦听到此ServerSocket的连接。此方法在进行连接之前一直阻塞。 Socket client=server.accept(); BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out=new PrintWriter(client.getOutputStream()); while(true){ [color=darkred]//从客户端接收输入[/color] String str=in.readLine(); System.out.println(str); [color=darkred]//向客户端写入信息[/color] out.println("has receive...."); out.flush(); if(str.equals("end")) break; } client.close(); } }
这个程序的主要目的在于服务器不断接收客户机所写入的信息只到.客户机发送"End"字符串就退出程序.并且服务器也会做出"Receive"为回应.告知客户机已接收到消息.
客户机代码:
import java.net.*; import java.io.*; public class Client{ static Socket server; public static void main(String[] args)throws Exception{ //创建服务器端对象server server=new Socket(InetAddress.getLocalHost(),5678); BufferedReader in=new BufferedReader(new InputStreamReader(server.getInputStream())); PrintWriter out=new PrintWriter(server.getOutputStream()); BufferedReader wt=new BufferedReader(new InputStreamReader(System.in)); while(true){ String str=wt.readLine(); out.println(str); out.flush(); if(str.equals("end")){ break; } System.out.println(in.readLine()); } server.close(); } }
客户机代码则是接受客户键盘输入,并把该信息输出,然后输出"End"用来做退出标识.
这个程序只是简单的两台计算机之间的通讯.如果是多个客户同时访问一个服务器呢?你可以试着再运行一个客户端,结果是会抛出异常的.那么多个客户端如何实现呢?
其实,简单的分析一下,就可以看出客户和服务通讯的主要通道就是Socket本身.而服务器通过accept方法就是同意和客户建立通讯.这样当客户建立Socket的同时.服务器也会使用这一根连线来先后通讯.那么既然如此只要我们存在多条连线就可以了.那么我们的程序可以变为如下:
服务器:
import java.io.*; import java.net.*; public class MyServer { public static void main(String[] args) throws IOException{ ServerSocket server=new ServerSocket(5678); while(true){ Socket client=server.accept(); BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out=new PrintWriter(client.getOutputStream()); while(true){ String str=in.readLine(); System.out.println(str); out.println("has receive...."); out.flush(); if(str.equals("end")) break; } client.close(); } } }
这里仅仅只是加了一个外层的While循环.这个循环的目的就是当一个客户进来就为它分配一个Socket直到这个客户完成一次和服务器的交互,这里也就是接受到客户的"End"消息.那么现在就实现了多客户之间的交互了.但是.问题又来了.这样做虽然解决了多客户,可是是排队执行的.也就是说当一个客户和服务器完成一次通讯之后下一个客户才可以进来和服务器交互.无法做到同时服务. 那么要如何才能同时达到既能相互之间交流又能同时交流呢?很显然这是一个并行执行的问题了.所以线程是最好的解决方案.
那么下面的问题是如何使用线程.首先要做的事情是创建线程并使得其可以和网络连线取得联系.然后由线程来执行刚才的操作.要创建线程要么直接继承Thread要么实现Runnable接口,要建立和Socket的联系只要传递引用就可以了.而要执行线程就必须重写run方法.而run方法所做的事情.就是刚才单线程版本main所做的事情.因此我们的程序变成了这样:
import java.net.*; import java.io.*; public class MultiUser extends Thread{ private Socket client; public MultiUser(Socket c){ this.client=c; } public void run(){ try{ BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out=new PrintWriter(client.getOutputStream()); //Mutil User but can't parallel while(true){ String str=in.readLine(); System.out.println(str); out.println("has receive...."); out.flush(); if(str.equals("end")) break; } client.close(); }catch(IOException ex){ }finally{ } } public static void main(String[] args)throws IOException{ ServerSocket server=new ServerSocket(5678); while(true){ //transfer location change Single User or Multi User MultiUser mu=new MultiUser(server.accept()); mu.start(); } } }
我的类直接从Thread类继承了下来.并且通过构造函数传递引用和客户Socket建立了联系.这样每个线程就有了.一个通讯管道.同样我们可以填写run方法.把之前的操作交给线程来完成.这样多客户并行的Socket就建立起来了.