----------------- 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培训 期待与您的交流----------------------------