Java---网络编程(3)-TCP-互传文件和图片

网友投稿 527 2022-05-29

☆ TCP

建立连接,形成传输数据的通道。

在连接中进行大数据量传输

通过三次握手完成连接,是可靠协议

必须建立连接,效率会稍低

Socket 和

ServerSocket类

TCP传输

TCP Socket:IP地址和端口,套接字

Socket和ServerSocket

建立客户端和服务器端

建立连接后,通过Socket中的IO流进行数据的传输

关闭socket

同样,客户端与服务器端是两个独立的应用程序。

TCP传输编程

☆基本思路(客户端)

客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。

连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream(), getOutputStream()获取即可。

与服务端通讯结束后,关闭Socket。

☆基本思路(服务器端)

服务端需要明确它要处理的数据是从哪个端口进入的。

当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。

当该客户端访问结束,关闭该客户端。

基于TCP的Socket通信流程

TCP传输编程代码:

☆客户端

通过Socket建立对象并指定要连接的服务端主机以及端口。

Socket s = new Socket(“192.168.1.1”,9999); OutputStream out = s.getOutputStream(); out.write(“hello”.getBytes()); s.close();

1

2

3

4

☆服务器端

建立服务端需要监听一个端口

ServerSocket ss = new ServerSocket(9999); Socket s = ss.accept (); InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int num = in.read(buf); String str = new String(buf,0,num); System.out.println(s.getInetAddress().toString()+”:”+str); s.close(); ss.close();

1

2

3

4

5

6

7

8

9

最简单的TCP演示实例:

客户端代码:

package cn.hncu.tcp; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; /** * 客户端 * @author 陈浩翔 * * 2016-5-10 */ public class MyClientSocket { public static void main(String[] args) { try { //因为是在自己本机上演示,IP就直接填写本机10.30.7.95的了。 //这个端口和IP都是服务器端的(自己可以改的) Socket s = new Socket("10.30.7.95", 9999); //和服务器进行三次握手,若失败则出异常,否则返回和对方通讯的socket OutputStream os = s.getOutputStream(); //发送数据 os.write("你好,服务器!".getBytes()); //接收服务器端的反馈 InputStream in = s.getInputStream(); DataInputStream din = new DataInputStream(in); System.out.println(din.readUTF()); s.close(); din.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }

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

服务器端代码:

package cn.hncu.tcp; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * 服务器端 * @author 陈浩翔 * * 2016-5-10 */ public class MyServerSocket { public static void main(String[] args) { try { ServerSocket server = new ServerSocket(9999); while(true){ System.out.println("准备接收一个数据..."); Socket s = server.accept();//阻塞式方法 System.out.println("接收了一个数据..."); //读--从客户端读数据 InputStream in = s.getInputStream(); byte buf[] = new byte[1024]; in.read(buf); System.out.println("read info: "+new String(buf)); //写--应答客户端--向他写数据 OutputStream out = s.getOutputStream(); DataOutputStream dout = new DataOutputStream(out); dout.writeUTF("你好,"+s.getInetAddress().getHostAddress()+" ,你的信息已收到。"); dout.close(); s.close(); } } catch (IOException e) { e.printStackTrace(); } } }

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

客户端运行结果:

你好,10.30.7.95 ,你的信息已收到。

1

2

服务器端运行结果:

☆思考

对于Web服务器而言,当有多个客户端同时访问服务器时,服务端又如何提供服务呢?

1

☆TCP传输最容易出现的问题

客户端连接上服务端,两端都在等待,没有任何数据传输。

通过例程分析:

因为read方法或者readLine方法是阻塞式。

解决办法:

自定义结束标记(必须定义传输文件中没有这个这个字符串的,不然会出现接收数据不完整)

使用shutdownInput,shutdownOutput方法。

编程练习

☆上传文本文件

读取一个本地文本文件,将数据发送到服务端,服务器端对数据进行存储。 存储完毕后,给客户端一个提示。

文本文件发送的客户端

package cn.hncu.tcp.upload; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; /** * 文本文件发送的客户端 * @author 陈浩翔 * * 2016-5-10 */ public class UploadTextClient { public static void main(String[] args) { try { Socket s = new Socket("", 10006); //思路:把本地文件的数据读取出来通过 s.getOutputStream()获得的out对象发送出去 BufferedReader bf = new BufferedReader(new FileReader("tempfiles\client.txt")); OutputStream out = s.getOutputStream();//这里的输出流 对应的是服务器端的输入流 PrintWriter pw = new PrintWriter(out,true);//建议不要用BufferedWriter //!!!!!!!!!!!!!!!!!这个true不要忘了!---自动刷新 //现在大家写网络传输文件,一般是用PrintWriter String str=null; while((str=bf.readLine())!=null){ pw.println(str); } //给服务器发送结束标记---上传结束,要加结束标记, //否则服务器在数据接收完毕时再调用read()或readLine()时会出异常 //法1:pw.println("over#$@#@$");//不能出现文件中存在的结束关键字---搞特殊一点 //法2---建议采用该种方式---由socket内部来指定结束标记 s.shutdownOutput(); bf.close(); //接收服务器端反馈 InputStream in = s.getInputStream(); DataInputStream din = new DataInputStream(in); System.out.println("server应答:"+din.readUTF()); s.close(); din.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }

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

文本文件接收的服务器端

package cn.hncu.tcp.upload; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; /** * 文本文件接收的服务器端 * @author 陈浩翔 * * 2016-5-10 */ public class UploadTextServer { public static void main(String[] args) { try { ServerSocket server = new ServerSocket(10006); Socket s = server.accept(); System.out.println(s.getInetAddress().getHostAddress()+"...发送消息来"); //读取客户端上传过来的文本文件 //源 ---socket(字节流)---额外:需要转换成字符流 ,缓存流 InputStream in = s.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); //目的 ---硬盘字符流 FileWriter---额外:打印流 PrintWriter pw = new PrintWriter(new FileWriter("tempfiles\server.txt"),true); String line = null; while((line=br.readLine())!=null){ // if("over#$@#@$".equals(line)){//自己定义的结束标志 // break; // } pw.println(line); } pw.close(); //上传成功,给客户端一个提示信息 OutputStream out = s.getOutputStream(); DataOutputStream dout = new DataOutputStream(out); dout.writeUTF("文件上传成功!"); s.close(); server.close(); dout.close(); } catch (IOException e) { e.printStackTrace(); } } }

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

测试通过!

☆上传图片文件

客户端需求:把一个图片文件发送到服务端并读取回馈信息。要求判断文件是否存在及格式是否为jpg或gif并要求文件小于2M。

服务端需求:接收客户端发送过来的图片数据。进行存储后,回馈一个 上传成功字样。支持多用户的并发访问。

图片文件的发送-客户端

package cn.hncu.tcp.upload; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; import javax.swing.JOptionPane; /** * 图片文件的发送-客户端 * @author 陈浩翔 * * 2016-5-10 */ public class UploadPicClient { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入图片路径:"); String str = sc.next(); File file = new File(str); if(!(file.exists()&& file.isFile())){ JOptionPane.showMessageDialog(null, "文件不存在!"); return ; } if(!(file.getName().endsWith(".jpg")||file.getName().endsWith(".gif"))){ JOptionPane.showMessageDialog(null, "文件格式不对,文件扩展名必须是jpg或gif!"); return ; } if( file.length()>=1024*1024*2){ JOptionPane.showMessageDialog(null, "文件过大,不应超过2M,请重新上传!"); return; } //上传 try { Socket s = new Socket("10.30.7.95", 10007); BufferedInputStream bin = new BufferedInputStream(new FileInputStream(str)); OutputStream out = s.getOutputStream(); byte buf[] = new byte[1024]; int len=0; while((len=bin.read(buf))!=-1){ out.write(buf, 0, len); } s.shutdownOutput();//告诉服务器,文件上传完毕 //读取服务器的回馈信息 InputStream in = s.getInputStream(); byte buf2[] = new byte[1024]; int len2 = in.read(buf2); System.out.println(new String(buf2, 0, len2)); //关流 out.close(); bin.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }

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

图片文件接收-服务器端

package cn.hncu.tcp.upload; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * 图片文件接收-服务器端 * @author 陈浩翔 * * 2016-5-10 */ public class UploadPicServer { public static void main(String[] args) { try { ServerSocket server = new ServerSocket(10007); while(true){ Socket s = server.accept();//阻塞方法 //只负责和客户端进行握手 new Thread(new UploadThread(s) ).start(); } } catch (IOException e) { e.printStackTrace(); } } } class UploadThread implements Runnable{ private Socket s; public UploadThread(Socket s) { this.s = s; } @Override public void run() { String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"...发来图片"); try { BufferedInputStream bin = new BufferedInputStream(s.getInputStream()); File dir = new File("g:\mypic"); if(!dir.exists()){ dir.mkdir();//文件夹不存在,创建mypic文件夹 } int count=1; //我觉得这里的后缀名,需要通过发送方也发过来的 File file = new File(dir, ip+".jpg"); while(file.exists()){ file = new File(dir,ip+"("+(count++) +")"+".jpg"); //带号的文件名 } FileOutputStream fout = new FileOutputStream(file); //从socket流中读取数据,存储到本地文件。相当于对拷 byte buf[] = new byte[1024]; int len=0; while( (len=bin.read(buf))!=-1){ fout.write(buf, 0, len); } //图片接收完毕 //向客户端发送回馈信息 OutputStream out = s.getOutputStream(); out.write( "上传成功".getBytes() ); fout.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } }

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

Java---网络编程(3)-TCP-互传文件和图片

81

82

83

84

85

86

87

88

有一个小bug。是服务端接收的,因为我把后缀名统一为jpg了,gif的图片可以上传,只是变成静图了(jpg)。可以通过改后缀名,再把这图片改回去动图。还有一种方法,在上传的时候,把后缀名也上传,再通过服务器解析就可以解决这个问题。

因为时间问题,我就不写了,这个很简单的。

只是多发送了一个后缀名过去而已。

我还是把那个后缀名的解决办法写了下:

在客户端:修改的代码如下:

//上传 try { Socket s = new Socket("10.30.7.95", 10007); BufferedInputStream bin = new BufferedInputStream(new FileInputStream(str)); //上传文件后缀###########增加的 OutputStream out = s.getOutputStream(); String fileName = file.getName(); out.write(fileName.substring(fileName.length()-4, fileName.length()).getBytes()); byte buf[] = new byte[1024]; int len=0; while((len=bin.read(buf))!=-1){ out.write(buf, 0, len); } s.shutdownOutput();//告诉服务器,文件上传完毕 //读取服务器的回馈信息 InputStream in = s.getInputStream(); byte buf2[] = new byte[1024]; int len2 = in.read(buf2); System.out.println(new String(buf2, 0, len2)); //关流 out.close(); bin.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }

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

服务器端:

@Override public void run() { String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"...发来图片"); try { BufferedInputStream bin = new BufferedInputStream(s.getInputStream()); File dir = new File("g:\\mypic"); if(!dir.exists()){ dir.mkdir();//文件夹不存在,创建mypic文件夹 } //读取上传过来的图片后缀是什么!######### char cbuf[] = new char[4]; InputStreamReader insr = new InputStreamReader(bin); insr.read(cbuf); String str = new String(cbuf); int count=1; //我觉得这里的后缀名,需要通过发送方也发过来的 File file = new File(dir, ip+str); while(file.exists()){ file = new File(dir,ip+"("+(count++) +")"+str); //带号的文件名 } FileOutputStream fout = new FileOutputStream(file); //从socket流中读取数据,存储到本地文件。相当于对拷 byte buf[] = new byte[1024]; int len=0; //#########必须有这一句 bin.read(buf, 0, 8); while( (len=bin.read(buf))!=-1){ fout.write(buf, 0, len); } //图片接收完毕 //向客户端发送回馈信息 OutputStream out = s.getOutputStream(); out.write( "上传成功".getBytes() ); fout.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } }

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

好了,基本上就是这样的,如果想要更好,做个图形界面就好看了。自己动下手吧~~

Java TCP/IP 网络

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:全网最全Python项目体系练习500例(附源代码),练完可就业
下一篇:一文入门ETCD
相关文章