黑马程序员_Java基础第24天_Java网络编程续

 

                                                          -----------------     Java培训   Android培训 期待与您的交流----------------------------

 

下面来完成一个传上传图片,这和前面的上传文件没有什么区别.只不过操作文件的时候使用的流对象是字节流而已! 我们来体验一下!

 

 

//服务器端
public class TcpImage {

	public static void main(String[] args) throws Exception {

		ServerSocket server = new ServerSocket(10909);
		Socket client = server.accept();
		// 获取客户端的输入流
		InputStream is = client.getInputStream();
		// 获取客户端的输出流
		OutputStream out = client.getOutputStream();
		// 文件存放的位置
		OutputStream os = new FileOutputStream("server.jpg");

		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = is.read(buffer)) != -1) {
			os.write(buffer, 0, len);
		}
		// 反馈信息给客户端
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
		bw.write("图片上传完成");
		bw.flush();
		os.close();
		client.close();
		server.close();
	}
}


 

// 客户端
class Client {
	public static void main(String[] args) throws Exception {
		// 创建客户端服务对象
		Socket socket = new Socket("192.168.1.102", 10909);
		InputStream in = new FileInputStream("D:\\imagetest\\desk.jpg");
		// 获取客户端的输出流对象
		OutputStream os = socket.getOutputStream();
		// 获取客户端的输入流对象
		InputStream is = socket.getInputStream();
		byte[] buffIn = new byte[1024];
		int len = 0;
		while ((len = in.read(buffIn)) != -1) {
			os.write(buffIn, 0, len);
		}
		// 告诉服务器我已经发送完毕
		socket.shutdownOutput();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String message = br.readLine();
		System.out.println(message);
		in.close();
		socket.close();
	}
}


我们知道这是单线程,一次只能服务一个客户端.当客户端A连接后,被服务器端获取到,服务器执行具体流程,这时B客户端连接,只能等待,因为服务器的端还没有处理完客户端A的请求,如果很多客户端都要和我这个服务器通讯的话,怎么办呢?最好服务器端将每个客户端封装到不同的线程里,这样就可以处理多个客户端请求.
现在我们来实现一下,多个客户端实现文件上传.
public class TcpThreads implements Runnable {
	private Socket socket;

	public TcpThreads(Socket socket) {
		this.socket = socket;
	}
	public void run() {
		int count = 1;
		String ip = socket.getInetAddress().getHostAddress();
		try {
			System.out.println(ip + "............connected");
			// 获取客户端的输入流

			File file = new File(ip + ".jpg");
			// 如果文件已经存在,则修改名称使之加一,直到名称不等
			while (file.exists())
				file = new File(ip + "(" + (count++) + ")" + ".jpg");
			InputStream is = socket.getInputStream();
			// 获取客户端的输出流
			OutputStream out = socket.getOutputStream();
			// 文件存放的位置
			OutputStream os = new FileOutputStream(file);

			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
			// 反馈信息给客户端
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
			bw.write("图片上传完成");
			bw.flush();
			os.close();
			socket.close();
		} catch (Exception e) {
			throw new RuntimeException(ip + "上传失败");
		}

	}
}


 

class ClientImage {
	public static void main(String[] args) throws Exception {
		if (args.length != 1) {
			System.out.println("请输入一个文件有效路径");
			return;
		}
		File file = new File(args[0]);

		if (!(file.exists() && file.isFile())) {
			System.out.println("该文件已经存在,或者不是一个文件");
			return;
		}
		long maxSize = 1024 * 1024 * 5;
		if (file.length() > maxSize) {
			System.out.println("文件不能大于5M");
			return;
		}

		if(!file.getName().endsWith(".jpg")){
			System.out.println("文件只能是JPG");
			return;
		}
		// 创建客户端服务对象
		Socket socket = new Socket("192.168.1.102", 12345);
		InputStream in = new FileInputStream(file);
		// 获取客户端的输出流对象
		OutputStream os = socket.getOutputStream();
		// 获取客户端的输入流对象
		InputStream is = socket.getInputStream();
		byte[] buffIn = new byte[1024];
		int len = 0;
		while ((len = in.read(buffIn)) != -1) {
			os.write(buffIn, 0, len);
		}
		// 告诉服务器我已经发送完毕
		socket.shutdownOutput();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String message = br.readLine();
		System.out.println(message);
		in.close();
		socket.close();
	}
}


 

class ServerImage {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(12345);
		while (true) {
			Socket socket = server.accept();// 阻塞式方法,当获取到客户端对象,就创建线程
			new Thread(new TcpThreads(socket)).start();
		}
	}
}


 

现在就可以对多个客户端服务了,看服务端的代码,while(true)说明服务器是一直开着的,
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(12345);
		while (true) {
			Socket socket = server.accept();// 阻塞式方法,当获取到客户端对象,就创建线程
			new Thread(new TcpThreads(socket)).start();
		}
	}


 

又因为accept是阻塞式方法,当没有客户端请求服务器时,服务器一直处于阻塞状态,直到有客户端请求,如果有多个客户端访问,也会创建一个新线程为该客户端服务,因为服务器处理代码已经封装到了run()方法里面去了!
现在实现一个与上面程序类似的小程序,-----TCP 客户端并发登录
 
每次看完老师写完代码,自己独立写出来,一开始总是报一些错误,只要自己仔细的分析,问题还是可以解决的,如果老师些一行你写一行我觉得这样的效果不好,自己只是,照着他实现了一遍,在脑里面的印象不是特别的深,如果自己独立写出来,虽然可能耗费几倍的时间,但是已经融入了自己的理解,也提高了自己解决问题的能力.当自己写完了,再和老师的对照,然后比较那个更好一些!
class ServerLogon implements Runnable {

	private Socket socket;

	public ServerLogon(Socket socket) {
		this.socket = socket;
	}

	public void run() {
	
		String ip = socket.getInetAddress().getHostAddress();
		try {
			//打印客户端的ip
			System.out.println(ip + "............. connected!");
			BufferedReader br = new BufferedReader(new InputStreamReader(socket
					.getInputStream()));

			PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
			
			// 只有三次尝试的机会
			for (int i = 0; i < 3; i++) {
				BufferedReader reader = new BufferedReader(new InputStreamReader(
						new FileInputStream("user.txt")));
				String username = br.readLine();
				//如果用户直接退出
				if (username == null) {
					break;
				}
				
				String line = null;
				boolean flag = false;
				while ((line = reader.readLine()) != null) {
					if (line.equals(username)) {
						flag = true;
						break;
					}
				}
				//如果用户名相同
				if (flag) {
					System.out.println(username + "登录成功");
					pw.println("欢迎登录");
					
				}else {
					System.out.println(username + "尝试登录");
					pw.println("无效的用户名");
				}
				reader.close();
			}
			socket.close();
			

		} catch (IOException e) {
			throw new RuntimeException(ip + "连接失败");
		}
	}
}


 

class UserClient {
	public static void main(String[] args) throws Exception {
		
		Socket socket = new Socket("192.168.1.102", 11111);
		PrintWriter bw = new PrintWriter(socket.getOutputStream(), true);
		BufferedReader in = new BufferedReader(new InputStreamReader(socket
				.getInputStream()));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		for (int i = 0; i < 3; i++) {
			String name = br.readLine();
			System.out.println(name);
			//如果客户端按Ctrl+c
			if (name == null)
				break;
			bw.println(name);
			String message = in.readLine();
			System.out.println(message);
			if (message.contains("欢迎")) {
				break;
			}
		}
		br.close();
		socket.close();

	}

}


 

public class TcpLogon {
	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(11111);
		while (true) {
			Socket socket = server.accept();
			new Thread(new ServerLogon(socket)).start();
		}
	}
}


 

 

 

 

用户信息如下所示:

 

我们写了这么多的客户端与服务端,程序不管是多线程还是单线程,它的总体思想是不变的,他们都是和流一起使用的,管服务器多么复杂,基本的原理还是这样的

学好这些,有助于我们以后理解学习和使用服务器如Tomcat等web服务器!

 

                          -----------------     Java培训   Android培训 期待与您的交流----------------------------

你可能感兴趣的:(黑马程序员)