【优化】IO流应用之网络传输

时间:2022-07-23 19:30:38

javase已经看到网络编程了,快结束啦!【优化】IO流应用之网络传输掌声鼓励下。。。呵呵

经过一个月的自学,基本把java基础语法掌握的差不多了。我发现学的越多,就越喜欢java代码的简洁,清晰,很享受写代码的过程!加油吧,骚年!【优化】IO流应用之网络传输接下来就是通过小项目练手了!

废话不多说,下面是昨天写的代码,通过这个例子,我发现优化代码真的很重要!!!!

需求是这样子的,

客户端通过键盘录入用户名
服务端对这个用户名进行校验

如果该用户存在 在服务端显示xxx已登录
并在客户端显示xxx 欢迎光临

如果该用户不存在,在服务端显示xxx,尝试登陆
并在客户端显示xxx,该用户不存在

最多就登陆三次。

环境,控制台。

下面是我的代码。

用户数据存放在data.txt中

 【优化】IO流应用之网络传输

 

/*
*本程序为方便调试,将客户端和服务端放在同一个.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值向客户端返回信息,很高效。

运行结果如下(同时打开两个控制台):

 【优化】IO流应用之网络传输

提示:需要先打开服务端!

这里注意一个细节,客户端和服务端都有这样一行代码:

if(line==null)

break;

这是因为如果客户端第一次登陆已经登陆成功的话,就不必要继续登陆了,这时按ctrl+c退出时,服务端并不结束,且其readLine方法会读到null值,所以

我们在客户端加上这句判断。

思考:优化后的代码其实还可以继续优化,例如我们的BufferedWriter类每次write之后都需要换行并刷新缓冲区,

很麻烦,可以用PrinterWriter类,自动刷新。