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

javase已经看到网络编程了,快结束啦!微笑掌声鼓励下。。。呵呵

经过一个月的自学,基本把java基础语法掌握的差不多了。我发现学的越多,就越喜欢java代码的简洁,清晰,很享受写代码的过程!加油吧,骚年!奋斗接下来就是通过小项目练手了!

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

需求是这样子的,

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

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

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

最多就登陆三次。

环境,控制台。

下面是我的代码。

用户数据存放在data.txt中

 【优化】IO流应用之网络传输_第1张图片

 

/*
 *本程序为方便调试,将客户端和服务端放在同一个.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流应用之网络传输_第2张图片

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

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

if(line==null)
			
    break;

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

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

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

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


 

 

你可能感兴趣的:(代码,IO流,IO流)