javase已经看到网络编程了,快结束啦!掌声鼓励下。。。呵呵
经过一个月的自学,基本把java基础语法掌握的差不多了。我发现学的越多,就越喜欢java代码的简洁,清晰,很享受写代码的过程!加油吧,骚年!接下来就是通过小项目练手了!
废话不多说,下面是昨天写的代码,通过这个例子,我发现优化代码真的很重要!!!!
需求是这样子的,
客户端通过键盘录入用户名
服务端对这个用户名进行校验
如果该用户存在 在服务端显示xxx已登录
并在客户端显示xxx 欢迎光临
如果该用户不存在,在服务端显示xxx,尝试登陆
并在客户端显示xxx,该用户不存在
最多就登陆三次。
环境,控制台。
下面是我的代码。
用户数据存放在data.txt中
/* *本程序为方便调试,将客户端和服务端放在同一个.java文件中, *另外将ip地址设置为127.0.0.1,仅限本机登陆,如果连有局域网,可以 *进行局域网登陆测试,本人亲测通过。(需先获取对方ip) */ import java.net.*; import java.io.*; import java.util.*; //客户端 class Client { //为保持代码简洁,这里抛出IO异常 public static void main(String[] args)throws IOException { //建立socket服务 Socket s=new Socket(InetAddress.getByName("127.0.0.1"),10006); BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));//键盘录入 BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream())); String line=null; for(int i=0;i<3;i++) { line=bufr.readLine(); if(line==null) break; //将登录名发给服务端 bufw.write(line); bufw.newLine(); bufw.flush(); //接收服务端反馈 String dataRe=bufIn.readLine(); System.out.println(dataRe); if(dataRe.contains("欢迎")) break; } s.close(); } } //服务端 class Server { public static void main(String[] args)throws IOException { //开启ServerSocket服务,监听一个端口 ServerSocket ss=new ServerSocket(10006); while(true) { Socket s=ss.accept(); //多线程处理并发登陆 new Thread(new LoginThread(s)).start(); } } } class LoginThread implements Runnable { private Socket socket; private ArrayList<String> arr; LoginThread(Socket socket) { this.socket=socket; } public void run() { try { System.out.println(socket.getInetAddress().getHostName()+"...connected"); File file=new File("data.txt"); //动态访问数据库,并遍历用户名,存入集合 BufferedReader buda=new BufferedReader(new FileReader(file)); String temp=null; arr=new ArrayList<String>(); while((temp=buda.readLine())!=null) { arr.add(temp); } //通过缓冲类包装getInputStream()和getOutputStream()方法 BufferedReader bufr=new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String line=null; //这里要求循环获取信息并反馈 for(int i=0;i<3;i++) { line=bufr.readLine();//获取客户端发来的信息 if(line==null) break; //遍历集合 Iterator<String> it=arr.iterator(); int count=0; while(it.hasNext()) { //检索到该用户名 if(it.next().equals(line)) { System.out.println(line+"已登录"); //反馈信息 bufw.write("尊敬的"+line+",欢迎光临"); bufw.newLine(); bufw.flush(); break; } else count++; } if(count==arr.size()) { System.out.println(line+"尝试登陆"); bufw.write(line+"用户不存在"); bufw.newLine(); bufw.flush(); } } socket.close();//超过三次,自动断开连接 } catch(IOException e) { throw new RuntimeException(); } } }
以上代码通过不够优化,特别是将文件中的数据存到集合中,每开启一个线程都会执行一次,效率很低,而且是通过计数器来判断返回信息的,比较低效。
下面将代码稍微优化一下。
import java.io.*; import java.net.*; //客户端 class NClient { public static void main(String[] args)throws IOException { //建立服务 Socket s=new Socket(InetAddress.getByName("127.0.0.1"),10006); BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); //键盘录入 BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream())); String line=null; String temp=null; for(int i=0;i<3;i++) { //读取键盘录入,写入流中,注意,因为有缓冲,必须换行并刷新 line=bufr.readLine(); if(line==null) break;//如果录入为空,则退出循环 bufw.write(line); bufw.newLine(); bufw.flush(); //接收服务端反馈 temp=bufIn.readLine(); System.out.println(temp); if(temp.contains("欢迎"))//登陆成功就退出循环 break; } s.close(); } } //服务端 class NServer { public static void main(String[] args)throws IOException { ServerSocket ss=new ServerSocket(10006); while(true) { Socket s=ss.accept(); new Thread(new LoginThread(s)).start(); } } } class LoginThread implements Runnable { private Socket s; LoginThread(Socket s) { this.s=s; } public void run() { System.out.println(s.getInetAddress().getHostAddress()+"....connected"); try { File file=new File("data.txt"); BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream())); BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); boolean flag=false; String line=null; for(int i=0;i<3;i++) { line=bufr.readLine(); if(line==null) break; BufferedReader buf=new BufferedReader(new FileReader(file)); String temp=null; while((temp=buf.readLine())!=null) if(line.equals(temp)) { flag=true; break; } if(flag) { System.out.println(line+"已登录"); bufw.write("尊敬的"+line+",欢迎光临"); bufw.newLine(); bufw.flush(); } else { System.out.println(line+"尝试登陆"); bufw.write(line+",该用户名不存在"); bufw.newLine(); bufw.flush(); } } s.close(); } catch(IOException e) { //throw new RuntimeException(); e.printStackTrace(); } } }
优化后的代码通过判断标记flag的boolean值向客户端返回信息,很高效。
运行结果如下(同时打开两个控制台):
提示:需要先打开服务端!
这里注意一个细节,客户端和服务端都有这样一行代码:
if(line==null) break;
这是因为如果客户端第一次登陆已经登陆成功的话,就不必要继续登陆了,这时按ctrl+c退出时,服务端并不结束,且其readLine方法会读到null值,所以
我们在客户端加上这句判断。
思考:优化后的代码其实还可以继续优化,例如我们的BufferedWriter类每次write之后都需要换行并刷新缓冲区,
很麻烦,可以用PrinterWriter类,自动刷新。