javase_22(TCP的学习-->*)

 

TCP传输

 

Socket(客户端)ServerSocket(服务端)

 

1.建立客户端和服务器端

 

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

 

3.关闭Socket()当关闭这个流,其实就是把底层的流所关闭

 

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

 

 

 

 

 

基本思路:(客户端)

 

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

 

 

 

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

 

getInputStream(), getOutputStream()获取即可.

 

 

 

与服务端通信结束,关闭Socket.

 

 

 

基本思路:(服务器端)

 

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

 

 

 

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

 

 

 

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

 

 

 

生动的比喻:

 

必须要建立114服务台,客户才可以拨打的道理..TCP服务器程序运行到ServerSocket.accept方法等待客户的连接,在正常的情况下,accept方法会发生阻塞,一直等到客户连接请求的到来.该方法才会返回.如果没有客户端请求来的情况下,accept方法没有发生阻塞,那么肯定前面的程序是有问题的.,通常端口被其他的程序所占用.

 

 

 

利用循环从客户端里面读取数据,并且在服务端显示出来?不要把问题那么复杂,该多线程就多线程-->该怎么走.比喻用到多线程.-->休息一下.等待它读取数据.要不然.我都还没有读取数据.-->你这边就已经执行了.

 

 

 

 

 

客户端

 

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

 

1 Socket s = new Sockte("127.0.0.0.1",8888);
2 InputStream ips = s.getInputS    tream();
3 OutputStream ops = s.getOutputStream();
4 S.close();//底层的流必须要关闭/.

服务端:

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

 

 1 ServerSocket ss = new ServerSocket(8888);
 2 //获取到客户端的Socket .
 3 Socket ss = Ss.accept();
 4 InputStream ips = s.getInputStream();
 5 OutputStream ops = s.getOutputStream();
 6 byte [] buf = new byte[1024];
 7 Ips.read(buf);
 8 int num = ips.read(buf);
 9 String str = new String(buf,0,num);
10 Ss.close();
11 S.close();

 

简单的TCP客户端与服务端:

 

客户端:

 

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.io.OutputStream;
 6 import java.net.Socket;
 7 
 8 public class TcpClient
 9 {
10 
11     /**
12      * 客户端
13      */
14     public static void main(String[] args)
15     {
16         Socket socket = null;
17         try
18         {
19             //连接到指定的主机端口号上
20             socket = new Socket("127.0.0.1",8888);
21             
22             //-->读取服务端的数据
23             InputStream ips = socket.getInputStream();
24             //-->发送服务端的数据
25             OutputStream ops = socket.getOutputStream();
26             ops.write("服务器你最近还好吗?".getBytes());//转换成字节流
27             ops.write("可以同时写两个数据吗??".getBytes());//转换成字节流
28             byte [] buf = new byte[ips.available()];
29             ips.read(buf);
30             System.out.println(new String(buf));
31         }
32         catch(IOException e)
33         {
34             
35         }finally
36         {
37             try
38             {
39                 if(socket!=null)
40                         socket.close();
41             }catch(IOException e)
42             {
43                 e.printStackTrace();
44             }
45         }
46         
47     }
48 
49 }

 

服务端:

 

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.io.OutputStream;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8 
 9 public class TcpServer
10 {
11     /*
12      * 服务端
13      */
14     public static void main(String[]args)
15     {
16         ServerSocket ss = null;;
17         Socket socket = null;
18         try
19         {
20             ss = new ServerSocket(8888);
21             socket = ss.accept();//监听端口--->和客户端已经绑定起来
22             InputStream ips = socket.getInputStream();
23             OutputStream ops = socket.getOutputStream();
24             byte[] buf = new byte[ips.available()];//个数为多少
25             ips.read(buf);
26             System.out.println(new String(buf));
27             ops.write("我最近过得还好~你不需要担心我服务器的寿命".getBytes());
28         }catch(IOException e)
29         {
30             e.printStackTrace();
31         }finally
32         {
33             try
34             {
35                 if(ss!=null)
36                     ss.close();
37             }catch(IOException e)
38             {
39                 e.printStackTrace();
40             }
41         }
42     }
43 }

 

字母转换大写功能:

客户端:

 

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.BufferedWriter;
 5 import java.io.IOException;
 6 import java.io.InputStream;
 7 import java.io.InputStreamReader;
 8 import java.io.OutputStream;
 9 import java.io.OutputStreamWriter;
10 import java.net.Socket;
11 
12 public class MyClient
13 {
14 
15     /**
16      *客户端
17      *循环边度边写的概念!!这一步不考虑多线程的问题
18      */
19     public static void main(String[] args)
20     {
21         Socket socket = null;
22         try
23         {
24             socket = new Socket("127.0.0.1",8888);
25             InputStream ips = socket.getInputStream();
26             OutputStream ops = socket.getOutputStream();
27             byte[]buf = new byte[ips.available()];
28             System.out.println(new String(buf));
29             System.out.println("请输入内容:");
30             while(true)
31             {
32                 BufferedReader br =
33                         new BufferedReader(new InputStreamReader(System.in));
34                     
35                 String line = br.readLine();
36                 if("quit".equals(line))
37                     break;
38                 ops.write((line+"\r\n").getBytes());
39                 byte[] b = new byte[ips.available()];
40                 ips.read(b);
41                 System.out.println("转换后的效果:"+new String(b));
42             }
43 
44         }catch(IOException e)
45         {
46             e.printStackTrace();
47         }finally
48         {
49             if(socket!=null)
50                 try
51                 {
52                     socket.close();
53                 } catch (IOException e)
54                 {
55                     // TODO Auto-generated catch block
56                     e.printStackTrace();
57                 }
58         }
59     }
60 
61 }

 

服务端:

 

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 import java.io.OutputStream;
 8 import java.net.ServerSocket;
 9 import java.net.Socket;
10 
11 public class MyServer
12 {
13     /**
14      * 服务端
15      */
16     public static void main(String[] args)
17     {
18         ServerSocket ss = null;
19         try
20         {
21             //监听端口
22             ss = new ServerSocket(8888);
23             Socket socket = ss.accept();//等待客户端的连接 返回连接后的对象
24             InputStream ips =socket.getInputStream();
25             OutputStream ops = socket.getOutputStream();
26             while(true)
27             {
28                 BufferedReader br = //把读取到的内容转换成字符流
29                         new BufferedReader(new InputStreamReader(ips));
30                 String line =  br.readLine();
31                 if("quit".equals(line))
32                     break;
33                 String toLine = line.toUpperCase();//转换成大写字母
34                 ops.write(toLine.getBytes());
35                  
36             }
37         }catch(IOException e)
38         {
39             e.printStackTrace();
40         }finally
41         {
42             if(ss!=null)
43                 try
44                 {
45                     ss.close();
46                 } catch (IOException e)
47                 {
48                     // TODO Auto-generated catch block
49                     e.printStackTrace();
50                 }
51         }
52     }
53 
54 }

 

一个程序开启了多线程-->Thread-0线程去执行..-->Main线程也在执行的.

必须让main线程等待一下.让其有一个消化的过程.

 

字母的转换:(使用了多线程解决问题)

客户端类

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 import java.io.OutputStream;
 8 import java.net.Socket;
 9 import java.net.UnknownHostException;
10 
11 public class ReverseClinet
12 {
13     public static void main(String[]args) throws InterruptedException, UnknownHostException, IOException
14     {
15             Socket socket = null;
16             socket = new Socket("127.0.0.1",8888);
17             InputStream ips = socket.getInputStream();
18             OutputStream ops = socket.getOutputStream();
19             //接收欢迎语,必须要先休息一下.因为那边写入数据.如果不休息.
20             //由于是开了线程执行的.main主线程就打印出来.所以打印到你的内容必定是空白的
21             Thread.sleep(10);
22             int len = ips.available();
23             byte[] buf = new byte[len];
24             ips.read(buf);
25             System.out.println(new String(buf));
26             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
27             System.out.println("开始吧!!");
28             while(true)
29             {
30                 String line = br.readLine();
31                 ops.write((line+"\r\n").getBytes());//写入进去
32                 int l = ips.available();
33                 byte[] b = new byte[l];
34                 Thread.sleep(10);
35                 ips.read(b);
36                 System.out.println(new String(b));
37             }
38     }
39 }

服务端:

 

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.IOException;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 
 7 /*
 8  * 服务器提供字符反向服务
 9  *多线程的思路:
10  *我等待用户的连接..当有用户连接.我交给别的线程去执行.对象是仍然没有变.-->socket重点.
11  *必须要循环监听.如果不循环监听...当一个服务端和客户端再运行..我就结束了..
12  */
13 public class ReverseServer
14 {
15     public static void main(String[]args)
16     {
17         ServerSocket ss = null;
18         try
19         {
20              ss = new ServerSocket(8888);
21             while(true)
22             {
23                 Socket socket = ss.accept();
24                 new Thread(new ReverseServers(socket)).start();
25             }
26         } catch (IOException e)
27         {
28             // TODO Auto-generated catch block
29             e.printStackTrace();
30         }finally
31         {
32             if(ss!=null)
33                 try
34                 {
35                     ss.close();
36                 } catch (IOException e)
37                 {
38                     // TODO Auto-generated catch block
39                     e.printStackTrace();
40                 }
41         }
42     }
43 }

 

-->它的哥们

 

 1 package com.javami.kudyDemo.Tcp;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 import java.io.OutputStream;
 8 import java.net.Socket;
 9 
10 public class ReverseServers implements Runnable
11 {
12     Socket socket ;
13     public  ReverseServers(Socket socket)
14     {
15         this.socket = socket;
16     }
17     public  void run()
18     {
19         try
20         {
21             InputStream ips = socket.getInputStream();
22             OutputStream ops = socket.getOutputStream();
23             ops.write("启动服务器提供反转功能:".getBytes());
24             while(true)
25             {
26                 BufferedReader br =
27                     new BufferedReader(new InputStreamReader(ips));//把读取到的数据转换成字符流
28                 String line = br.readLine();
29                 if("quit".equals(line))
30                     break;
31                 StringBuilder sb = new StringBuilder(line);
32                 String newLine = sb.reverse().toString();//转换
33                 ops.write(newLine.getBytes());
34             }
35         }catch(IOException e)
36         {
37             e.printStackTrace();
38         }finally
39         {
40             if(socket!=null)
41                 try
42                 {
43                     socket.close();
44                 } catch (IOException e)
45                 {
46                     // TODO Auto-generated catch block
47                     e.printStackTrace();
48                 }
49         }
50     }
51 }

 

TCP网络程序的工作原理:

 

TCP客户端程序与TCP服务端程序的交互过程:

1.服务器端程序创建一个ServerSocket,然后调用accpept方法等待客户来连接.

2.客户端程序创建一个Socket并请求服务端建立连接.

3.服务器端接收客户的连接请求,并创建一个新的Socket与该客户建立专线连接.

4.建立了连接的两个Socket在一个单独的线程(由服务端程序创建)上对话.

5.服务器端开始等待i新的连接请求,当新的连接请求到达时,重复上述过程.

 

 

 

 

文件上传案例分析

一、需求分析

1.多线程的服务器

2.客户端程序

3.上传文件名

4.上传文件

 

二、实现步骤

1.实现多线程服务器

1)创建ServerSocket对象,监听指定的端口,7888

2)循环调用accept方法,等待客户端的连接,次方法阻塞,返回一个客户端Socket

3)开启新线程,运行一个服务对象,将socket给这个对象

2.实现客户端程序

1)创建Socket对象,连接服务器  127.0.0.1  7888

3.发送和接收欢迎语

服务器端: 获得输入输出流, 发送欢迎语, out.write();

客户端: 获得输入输出流, 接收欢迎语, in.read();

4.发送文件名,创建文件

1)客户端:

读键盘,获得文件路径名 BufferedReader

创建文件对象, File

判断文件是否存在,文件是否为标准文件 isFile

获得文件名:getName

将文件名上传给服务器,out.write

等待接收服务器反馈的信息

2)服务器端:

接收文件名,in.read();

创建文件对象, 在指定目录下创建 createNewFile

判断是否创建成功,文件已存在或创建失败, 将是否可以继续上传的信息发给客户端 out.write

5.上传文件

1)客户端:

如果可以开始上传文件了

BufferedInputStream包装FileInputStream

BufferedOutputStream包装 socket.getOutputStream()

实现流的对拷,逐个字节拷贝,

2)服务器端

接收客户端上传的数据写入新创建的文件中

BufferedInputStream包装socket.getInputStream()

BufferedOutputStream包装 FileOutputStream

实现流的对拷,逐个字节拷贝。

 

文件的上传功能小项目

 

客户端:

 

 1 package com.javami.kudyDemo;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.BufferedOutputStream;
 5 import java.io.BufferedReader;
 6 import java.io.File;
 7 import java.io.FileInputStream;
 8 import java.io.IOException;
 9 import java.io.InputStream;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.net.Socket;
13 
14 public class UploadClient
15 {
16 
17     public static void main(String[] args)
18     {
19         Socket socket = null;
20         try
21         {
22             socket = new Socket("127.0.0.1",8888);
23             InputStream ips = socket.getInputStream();
24             OutputStream ops = socket.getOutputStream();
25             //接收欢迎语句
26             Thread.sleep(10);//-->等待线程的写入
27             int len = ips.available();
28             byte[] buf = new byte[len];
29             ips.read(buf);
30             System.out.println(new String(buf));
31             
32             //上传文件名
33             BufferedReader br =
34                     new BufferedReader(new InputStreamReader(System.in));
35             System.out.println("请输入你的文件名:");
36             File file = null;
37             while(true)
38             {
39                 String fileName = br.readLine();
40                 if("quit".equals(fileName))
41                         return ;
42                 file = new File(fileName);
43                 if(file.isFile())
44                 {
45                     ops.write(file.getName().getBytes());
46                     break;//如果是文件--写入进去
47                 }
48                 if(!file.isFile())
49                     System.out.println("该文件不存在,请重新输入");
50                 else
51                     System.out.println("只支持标准文件的上传");
52             }
53             
54             //等待服务端的反馈:
55             buf = new byte[1024];
56             len = ips.read(buf);
57             String info = new String(buf,0,len);
58             System.out.println(info);
59             if(!"可以上传文件".equals(info))
60                 return;
61             long fileSize = file.length();
62             ops.write(String.valueOf(fileSize).getBytes());
63             Thread.sleep(100);
64             
65             //上传文件
66             upload(file,ops);
67             
68             //等待服务端的反馈
69             len = ips.read(buf);
70             System.out.println(new String(buf,0,len));
71         }catch(Exception  e)
72         {
73             e.printStackTrace();
74         }finally
75         {
76             
77         }
78     }
79 
80     private static void upload(File file, OutputStream ops) throws IOException
81     {
82         BufferedInputStream bis = 
83                 new BufferedInputStream(new FileInputStream(file));//读取林的内容
84         BufferedOutputStream bos = new BufferedOutputStream(ops);//写入内容
85         System.out.println("文件上传中~~~~");
86         int ch ;
87         while((ch=bis.read())!=-1)
88         {
89             bos.write(ch);
90         }
91         bos.flush();//这个刷新一下就可以.因为让底层去关.要不然就会发生冲突
92         bis.close();//这个必须要关
93     }
94 
95 }

 

 

 

 

 

 

 

 

 

 

 

服务端:

 

 1 package com.javami.kudyDemo;
 2 
 3 import java.io.IOException;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 
 7 public class UploadServer
 8 {
 9     /*
10      * 必须要用到多线程去做.如果你没有使用多线程..那么main线程只能和一个连接打交道..
11      * while
12      * 
13      */
14     public static void main(String[]args)
15     {
16         ServerSocket ss = null;
17         try
18         {
19             System.out.println("服务器已经开启,正在监听8888端口");
20             ss = new ServerSocket(8888);
21             while(true)//我while循环没有结束-->在监听啦~~~
22             {        
23                 Socket socket = ss.accept();//当每一个线程都进来的时候,这里会发生阻塞
24                 System.out.println("成功与一个客户端建立连接"+
25                             socket.getInetAddress().getHostAddress());
26                 new Thread(new UploadServers(socket)).start();
27             }
28         } catch (IOException e)
29         {
30             // TODO Auto-generated catch block
31             e.printStackTrace();
32         }finally
33         {
34             if(ss!=null)
35                 try
36                 {
37                     ss.close();
38                 } catch (IOException e)
39                 {
40                     // TODO Auto-generated catch block
41                     e.printStackTrace();
42                 }
43         }
44     }
45 }

 

客户端的哥们-->

 

 1 package com.javami.kudyDemo;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.BufferedOutputStream;
 5 import java.io.File;
 6 import java.io.FileOutputStream;
 7 import java.io.IOException;
 8 import java.io.InputStream;
 9 import java.io.OutputStream;
10 import java.net.Socket;
11 
12 public class UploadServers implements Runnable
13 {
14 
15     Socket socket ;
16     public UploadServers(Socket socket)
17     {
18         this.socket = socket;
19     }
20 
21     @Override
22     public void run()
23     {
24         try
25         {
26             InputStream ips = socket.getInputStream();
27             OutputStream ops = socket.getOutputStream();
28             ops.write("连接成功,本站支持文件的上传".getBytes());
29             
30             //接收文件名
31             byte[] buf = new byte[1024];
32             int len = ips.read(buf);
33             String fileName = new String(buf,0,len);
34             System.out.println("拿到文件名:"+fileName);
35             
36             //创建文件
37             File file = new File("f:/a",fileName);
38             if(!file.createNewFile())
39             {
40                 ops.write("该文件已经存在".getBytes());
41                 return;
42             }
43             ops.write("可以上传文件".getBytes());
44             
45             //接收文件的大小
46             len = ips.read(buf);
47             String str = new String(buf,0,len);
48             int fileSize = (int)Integer.parseInt(str);
49             
50             //接收客户端的文件
51             saveFile(ips,file,fileSize);//接收的内容.我的文件名  --> 接收过来的长度
52             //接收从客户端发送过来的文件
53             ops.write("文件上传完毕,恭喜-->使用了".getBytes());
54         } catch (IOException e)
55         {
56             // TODO Auto-generated catch block
57             e.printStackTrace();
58         }
59         
60     }
61 
62     private void saveFile(InputStream ips, File file, int fileSize) throws IOException
63     {
64         BufferedInputStream bis = 
65                 new BufferedInputStream(ips);//读取内容-->会发生阻塞..
66         BufferedOutputStream bos = 
67                 new BufferedOutputStream(new FileOutputStream(file));
68         int ch;
69         System.out.println("文件上传中,请等下------");
70         for(int i=0; i<fileSize; i++)
71         {
72             ch = bis.read();
73             bos.write(ch);
74         }
75         bos.close();//不需要把底层的所关闭~~
76     }
77 
78 }

 

 

 

 

 

posted @ 2012-09-02 12:49  自学_更是一种信仰  阅读(226)  评论(0编辑  收藏  举报