JAVA之旅(三十三)——TCP传输,互相(伤害)传输,复制文件,上传图片,多并发上传,多并发登录
我们继续网络编程
一.TCP
说完UDP,我们就来说下我们应该重点掌握的TCP了
-
TCP传输
-
Socket和ServiceSocket
- 建立客户端和服务端
- 建立连接后,通过Socket中的IO流进行数据的传输
- 关闭Socket
同样的,我们的客户端和服务端都是两个独立的应用
我们通过查阅API文档发现,该对象在建立的时候,就可以去连接指定主机,因为tcp是面向连接的,所以在建立socket服务时,就要有服务存在,并成功连接,形成通路后,在该通道进行数据传输
所以我们用代码来看下他的步骤
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 1package com.lgl.hellojava;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.io.OutputStream;
6import java.net.ServerSocket;
7import java.net.Socket;
8import java.net.UnknownHostException;
9
10public class TcpClient {
11
12 public static void main(String[] args) {
13 try {
14 //1.创建客户端的服务,传地址和端口
15 Socket s = new Socket("192.168.1.102",10000);
16 //2.为了发送数据,应该获得socket流中的输出流
17 OutputStream out = s.getOutputStream();
18 out.write("你好".getBytes());
19 s.close();
20 } catch (UnknownHostException e) {
21 // TODO Auto-generated catch block
22 e.printStackTrace();
23 } catch (IOException e) {
24 // TODO Auto-generated catch block
25 e.printStackTrace();
26 }
27 }
28}
29
30
31
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 1package com.lgl.hellojava;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.net.ServerSocket;
6import java.net.Socket;
7
8/**
9 * 定义端点接收数据打印出来
10 * 服务端:
11 * 1.建立服务端的socket服务,servicesocket,并监听一个端口
12 * 2.获取连接过来的客户端对象,通过accept方法,这个方法是阻塞的,没有连接就会等
13 * 3.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该对象的读取流
14 * 4.关闭服务端(可选操作)
15 * @author LGL
16 *
17 */
18public class TcpService {
19 public static void main(String[] args) {
20 try {
21 //1.建立连接,监听端口
22 ServerSocket ss = new ServerSocket(10000);
23 //2.连接客户端对象
24 Socket accept = ss.accept();
25 //获取ip
26 String ip = accept.getInetAddress().getHostAddress();
27 //3.获取客户端发送过来的数据
28 InputStream in = accept.getInputStream();
29 //4.开始读取
30 byte [] buf = new byte[1024];
31 int len = in.read(buf);
32 System.out.println(new String(buf,0,len));
33 //5.关闭
34 ss.close();
35 } catch (IOException e) {
36 // TODO Auto-generated catch block
37 e.printStackTrace();
38 }
39 }
40}
41
42
二.TCP互相传输
我们在来写一个实例去说明,他们的互访动作,这里为了写起来方便,就写在一个类中了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 1package com.lgl.hellojava;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.io.OutputStream;
6import java.net.ServerSocket;
7import java.net.Socket;
8import java.net.UnknownHostException;
9
10/**
11 * 客户端发送信息,服务端收到,反馈信息
12 *
13 * @author LGL
14 *
15 */
16public class Tcp {
17
18 public static void main(String[] args) {
19 try {
20 Socket s = new Socket("192.168.1.102", 10005);
21 OutputStream out = s.getOutputStream();
22 out.write("我是客户端".getBytes());
23 InputStream in = s.getInputStream();
24 byte[] buf = new byte[1024];
25 int len = in.read(buf);
26 System.out.println(new String(buf, 0, len));
27 s.close();
28 } catch (UnknownHostException e) {
29 // TODO Auto-generated catch block
30 e.printStackTrace();
31 } catch (IOException e) {
32 // TODO Auto-generated catch block
33 e.printStackTrace();
34 }
35 }
36}
37/**
38 * 服务端
39 * @author LGL
40 *
41 */
42class Server {
43 public static void main(String[] args) {
44 try {
45 ServerSocket ss = new ServerSocket(10005);
46 Socket s = ss.accept();
47 InputStream in = s.getInputStream();
48 byte[] buf = new byte[1024];
49 int len = in.read(buf);
50 System.out.println(new String(buf, 0, len));
51
52 OutputStream out = s.getOutputStream();
53 out.write("收到后反馈".getBytes());
54 s.close();
55 ss.close();
56 } catch (IOException e) {
57 // TODO Auto-generated catch block
58 e.printStackTrace();
59 }
60 }
61}
62
63
三.复制文件
同样的这里也是使用的流,我们具体来看下怎么去操作,我们同样的,写在一个类中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 1package com.lgl.socket;
2
3import java.io.BufferedReader;
4import java.io.FileReader;
5import java.io.FileWriter;
6import java.io.IOException;
7import java.io.InputStreamReader;
8import java.io.PrintWriter;
9import java.net.ServerSocket;
10import java.net.Socket;
11import java.net.UnknownHostException;
12
13public class FileClient {
14
15 public static void main(String[] args) {
16 try {
17 Socket s = new Socket("192.168.1.102", 10006);
18 BufferedReader bufr = new BufferedReader(new FileReader("test.txt"));
19 PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
20 String line = null;
21 while ((line = bufr.readLine()) != null) {
22 pw.println(line);
23 }
24 pw.print("over");
25 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
26 s.getInputStream()));
27 String str = bufIn.readLine();
28 System.out.println(str);
29
30 bufr.close();
31 s.close();
32 } catch (UnknownHostException e) {
33 // TODO Auto-generated catch block
34 e.printStackTrace();
35 } catch (IOException e) {
36 // TODO Auto-generated catch block
37 e.printStackTrace();
38 }
39 }
40}
41
42class FileServer {
43 public static void main(String[] args) {
44 try {
45 ServerSocket ss = new ServerSocket(10006);
46 Socket s = ss.accept();
47
48 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
49 s.getInputStream()));
50 PrintWriter out = new PrintWriter(new FileWriter("test1.txt"), true);
51 String line = null;
52 while ((line = bufIn.readLine()) != null) {
53 if ("over".equals(line))
54 break;
55 out.println(line);
56 }
57 PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
58 pw.println("上传成功");
59
60 out.close();
61 s.close();
62 ss.close();
63
64 } catch (IOException e) {
65 // TODO Auto-generated catch block
66 e.printStackTrace();
67 }
68 }
69}
70
71
四.上传图片
我们再来看下图片是怎么上传的,我们先来分析下步骤
客户端
-
1.服务端点
-
2.读取客户端已有的图片数据
-
3.通过socket,发送给服务端
-
4.读取服务端反馈的信息
-
5.关闭资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 1**
2 * 客户端
3 *
4 * @author LGL
5 *
6 */
7public class PicClient {
8
9 public static void main(String[] args) {
10 try {
11 Socket s = new Socket("192.168.1.102", 10009);
12 FileInputStream fis = new FileInputStream("1.png");
13 OutputStream out = s.getOutputStream();
14 byte[] buf = new byte[1024];
15 int len = 0;
16 while ((len = fis.read(buf)) != -1) {
17 out.write(buf, 0, len);
18 }
19 //告訴服务端数据写完
20 s.shutdownInput();
21 InputStream in = s.getInputStream();
22 byte[] bufn = new byte[1024];
23 int num = in.read(bufn);
24 System.out.println(new String(bufn, 0, num));
25 fis.close();
26 s.close();
27 } catch (UnknownHostException e) {
28 // TODO Auto-generated catch block
29 e.printStackTrace();
30 } catch (IOException e) {
31 // TODO Auto-generated catch block
32 e.printStackTrace();
33 }
34 }
35}
36
37
服务端
直接看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 1
2/**
3 * 服務端
4 * @author LGL
5 *
6 */
7class PicServer {
8 public static void main(String[] args) {
9 try {
10 ServerSocket ss = new ServerSocket(10009);
11 Socket s = ss.accept();
12 InputStream in = s.getInputStream();
13 FileOutputStream fos = new FileOutputStream("2.png");
14 byte[] buf = new byte[1024];
15 int len = 0;
16 while ((len = in.read(buf)) != -1) {
17 fos.write(buf, 0, len);
18 }
19
20 OutputStream out = s.getOutputStream();
21 out.write("上传成功".getBytes());
22 fos.close();
23 s.close();
24 ss.close();
25 } catch (IOException e) {
26 // TODO Auto-generated catch block
27 e.printStackTrace();
28 }
29 }
30}
31
其实跟I/O区别真不大,但是概念一定要了解清楚
五.多并发上传
多并发这个概念就是多人互动了,这对服务器的负荷还是有考究的,这里呢,我们就模拟一下,多人上传图片的场景,我们是怎么做的?我们还是在上传图片的那份代码上更改
首先我们可以确定的是,这是服务端的代码
- 这个服务端有个局限性,当A客户端连接之后,被服务端获取到,服务端就在执行代码了,这个时候如果B客户端连接只有等待,这就是我们需要多并发的原因了,为了让多个客户端同时连接,服务端最好就是讲每个客户端封装到一个单独的线程中,这样就可以同时处理多个客户端请求
如何定义线程?
-
只要明确了每个客户端要在服务端执行的代码即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 1
2/**
3 * 服務端
4 *
5 * @author LGL
6 *
7 */
8class PicServer {
9 public static void main(String[] args) {
10 try {
11 ServerSocket ss = new ServerSocket(10009);
12 while (true) {
13 Socket s = ss.accept();
14 new Thread(new PicThread(s)).start();
15 }
16 } catch (IOException e) {
17 // TODO Auto-generated catch block
18 e.printStackTrace();
19 }
20 }
21}
22/**
23 * 并发线程
24 * @author LGL
25 *
26 */
27class PicThread implements Runnable {
28
29 private Socket s;
30
31 public PicThread(Socket s) {
32 this.s = s;
33 }
34
35 @Override
36 public void run() {
37 try {
38 String ip = s.getInetAddress().getHostAddress();
39 System.out.println("ip:" + ip);
40
41 long millis = System.currentTimeMillis();
42 File file = new File(millis + ".png");
43 InputStream in = s.getInputStream();
44 FileOutputStream fos = new FileOutputStream(file);
45 byte[] buf = new byte[1024];
46 int len = 0;
47 while ((len = in.read(buf)) != -1) {
48 fos.write(buf, 0, len);
49 }
50
51 OutputStream out = s.getOutputStream();
52 out.write("上传成功".getBytes());
53 fos.close();
54 s.close();
55 } catch (Exception e) {
56
57 throw new RuntimeException("上传失败");
58 }
59
60 }
61
62}
63
其实我写的代码还是有点烂的,但是思想在就好,我们得先把思想学会了
六.多并发登录
上面说的多并发的上传,实在服务端端,现在我们来说下登录,是作用在客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 1package com.lgl.socket;
2
3import java.io.BufferedReader;
4import java.io.FileReader;
5import java.io.IOException;
6import java.io.InputStreamReader;
7import java.io.PrintWriter;
8import java.net.ServerSocket;
9import java.net.Socket;
10import java.net.UnknownHostException;
11
12public class LoginClient {
13
14 public static void main(String[] args) {
15 try {
16 Socket s = new Socket("192.168.1.102", 10008);
17 BufferedReader bufr = new BufferedReader(new InputStreamReader(
18 System.in));
19 PrintWriter out = new PrintWriter(s.getOutputStream(), true);
20 BufferedReader bufIn = new BufferedReader(new InputStreamReader(
21 s.getInputStream()));
22 for (int i = 0; i < 3; i++) {
23 String line = bufr.readLine();
24 if (line == null) {
25 break;
26 }
27 out.println(line);
28
29 String info = bufIn.readLine();
30 System.out.println("info:" + info);
31 if (info.contains("欢迎")) {
32 break;
33 }
34 }
35 bufr.close();
36 s.close();
37 } catch (UnknownHostException e) {
38 // TODO Auto-generated catch block
39 e.printStackTrace();
40 } catch (IOException e) {
41 // TODO Auto-generated catch block
42 e.printStackTrace();
43 }
44 }
45}
46
47/**
48 * 服务端
49 *
50 * @author LGL
51 *
52 */
53class LoginServer {
54 public static void main(String[] args) {
55 try {
56 ServerSocket ss = new ServerSocket(10008);
57 while (true) {
58 Socket s = ss.accept();
59 new Thread(new UserThread(s)).start();
60 }
61 } catch (IOException e) {
62 // TODO Auto-generated catch block
63 e.printStackTrace();
64 }
65 }
66}
67
68/**
69 * 并发登陆
70 *
71 * @author LGL
72 *
73 */
74class UserThread implements Runnable {
75
76 private Socket s;
77
78 public UserThread(Socket s) {
79 this.s = s;
80 }
81
82 @Override
83 public void run() {
84 for (int i = 0; i < 3; i++) {
85 try {
86 BufferedReader bufrIn = new BufferedReader(
87 new InputStreamReader(s.getInputStream()));
88 String name = bufrIn.readLine();
89
90 // 模拟读取数据库的用户名
91 BufferedReader bufr = new BufferedReader(new FileReader(
92 "user.txt"));
93
94 PrintWriter out = new PrintWriter(s.getOutputStream(), true);
95
96 String line = null;
97
98 boolean flag = false;
99 while ((line = bufr.readLine()) != null) {
100 if (line.equals(name)) {
101 flag = true;
102 break;
103 }
104 }
105 if (flag) {
106 System.out.println("已登录");
107 out.print("欢迎");
108 } else {
109 System.out.println("重新登录");
110 out.println("用户名不存在");
111 }
112 s.close();
113
114 } catch (IOException e) {
115 // TODO Auto-generated catch block
116 e.printStackTrace();
117 }
118
119 }
120 }
121
122}
123
OK,这些代码中可能会存在一些错误,因为代码并没有去实际的验证中,我写的时候也是跟着思想去走的,这样写代码是极为友好的,这就是TCP的冰山一角了,不过关于这些,还有很多知识点,我们要做的就是把思想给掌握了,万变不理其中
好的,最近写文的时间,有点懈怠了,看来要发力了,嘻嘻,