网络编程——第一部分

 

新博客地址:Temi

第一讲,第二讲:Java基础第23天-01-网络编程(概述),第23天-02-网络编程(概述2)

一,网络通信步骤:

    1. 找到对方(通过IP)。
    2. 数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。====端口(逻辑端口)====
    3. 定义通信规则,这个规则成为协议。国际标准化组织定义了TCP/IP协议。======有效端口:0 ~65535,系统使用或保留的端口是:0~ 1024。======

第三讲:(网络模型)

 

一,各个层次的协议   (通常用户操作的是应用层,而编程人员需要做的是传输层和网际层)

    1. 网际层:IP协议。
    2. 传输层:TCP/UDP协议。
    3. 应用层:HTTP/FTP 协议。(web开发)。

二,网络通讯要素:

  1. IP地址:
    1. 网络中设备的标识。
    2. 不易记忆,可用主机名。
    3. 本地回环地址。127.0.0.1  。主机名:localhost
  2. 端口号:
    1. 用于表示进程的逻辑地址。不同进程的标识。
    2. 有效端口:0-65535,其中1-1024系统使用或保留端口。

三,涉及到的类:

    1. public class InetAddress extends Object implements Serializable       此类表示互联网协议 (IP) 地址。   ====注:此类没有构造方法=====
    2. 方法:public static InetAddress  getByName (String host)  throws UnknownHostException   在给定主机名的情况下确定主机的 IP 地址。
    3. 方法:public static InetAddress[] getAllByName(String host) throws UnknownHostException      在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
    4. 方法:public static InetAddress getByAddress(byte[] addr) throws UnknownHostException      在给定原始 IP 地址的情况下,返回 InetAddress 对象。
    5. 方法:public String getHostName()    获取此 IP 地址的主机名。
    6. 方法:public String getHostAddress()  返回 IP 地址字符串(以文本表现形式)。

四,代码练习:

 1 import java.net.*;
 2 
 3 public class IPDemo {
 4              public static void main(String[] args) throws UnknownHostException {
 5                              //声明地址类,表示本地主机
 6                              InetAddress i = InetAddress.getLocalHost();
 7                              
 8                              //输出本地主机的IP地址
 9                              System.out.println(i.getHostAddress());
10                              
11                              //已主机名的方式找到主机
12                              InetAddress my = InetAddress.getByName("Lenovo-PC");
13                              
14                              //输出主机地址
15                              System.out.println(my.getHostAddress());
16                              
17                              
18                              //获取百度所有主机
19                              InetAddress[] ia = InetAddress.getAllByName("www.baidu.com");
20                              
21                              //输出百度主机地址
22                              for(InetAddress inet : ia){
23                                  
24                                  System.out.println(inet.getHostName()+"::"+inet.getHostAddress());
25                              }
26                               
27             }
28 }

第四讲:网络编程(IP地址)

第五讲:网络编程(TCP和UDP)

一,TCP 和 UDP 简介:

  1. UDP(面向无连接,明确了对方的端口,无论在不在网上,只管传输,不在就会丢失数据。只求速度,应用于网络视频会议和聊天等应用程序中。)
    1. 将数据及源和目的封装在数据包中,不需要建立连接。
    2. 每个数据包的大小限制在64k内。
    3. 因为无连接,是不可靠协议。
    4. 不需要建立连接,所以速度快。
  2. TCP( 是面向连接的,必须连接成功才能传输数据,应用于下载等程序上)
    1. 建立连接形成传输数据的通道。
    2. 可在连接中进行大数据量传输。
    3. 通过三次握手完成数据连接,是可靠协议。===注:三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方再次确认连接成功。====
    4. 必须建立连接,效率稍低。

第六讲,第七讲:网络编程(Socket),网络编程(Udp-发送端)

一,Socket 简介:

    1. Socket 是为网络服务提供的一种机制。
    2. 通信的两段都有Socket。
    3. 网络通信其实就是Socket之间的通信。
    4. 数据在两个Socket之间通过IO传输。

二,DatagramSocket 类简介:

    1. public class DatagramSocketextends Object   此类表示用来发送和接收数据报包的套接字。   ===注:在 DatagramSocket 上总是启用 UDP 广播发送。====
    2. 构造方法:public DatagramSocket() throws SocketException   构造数据报套接字并将其绑定到本地主机上任何可用的端口。
    3. 构造方法:public DatagramSocket(int port) throws SocketException   创建数据报套接字并将其绑定到本地主机上的指定端口。
    4. 方法:public InetAddress getInetAddress()       返回此套接字连接的地址。如果套接字未连接,则返回 null。
    5. 方法:public int getPort()     返回此套接字的端口。如果套接字未连接,则返回 -1。
    6. public void send (DatagramPacket p) throws IOException 从此套接字发送数据报包。

三,DatagramPacket 类简介(DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。):

    1. public final class DatagramPacketextends Object           此类表示数据报包。
    2. 构造方法:public DatagramPacket(byte[] buf, int offset, int length, InetAddress address,int port)  构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
    3. 方法:public InetAddress getAddress()  返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
    4. 方法:public int getPort()                    返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
    5. 方法:public byte[] getData()             返回数据缓冲区。接收到的或将要发送的数据从缓冲区中的偏移量 offset 处开始,持续 length 长度。
    6. 方法:public int getOffset()                返回将要发送或接收到的数据的偏移量。
    7. 方法:public int getLength()               返回将要发送或接收到的数据的长度。

四,代码练习:

 1 import java.net.*;
 2 
 3 public class UdpSend {
 4              public static void main(String[] args) throws Exception {
 5                  
 6                              //创建Udp服务
 7                            DatagramSocket ds = new DatagramSocket();
 8                            
 9                            //获得发送数据
10                            byte[] b = "这是发送信息".getBytes();
11                            
12                            //构造数据包
13                            DatagramPacket dp = new DatagramPacket(b, b.length,InetAddress.getByName("localhost"),8080);
14                            
15                            //发送数据
16                            ds.send(dp);
17                            
18                            //关闭资源
19                            ds.close();
20             }
21 }

第八讲:网络编程(Udp-接收端)

一,Udp 的 Socket 服务建立步骤。

    1. 建立DatagramSocket和DatagramPacket对象。
    2. 建立发送端(建立UDPSocket服务,在此无需指定端口,也可以将端口加入。如果不指定的话,系统会随机分配一个端口,如第一次运行时端口为1093,那么第二次就会顺延为1094,再运行会一直顺延,因为之前的端口还没有得到释放,所以会顺延端口号值。),接受端(定义UDPSocket服务。通常会监听一个端口,其实就是给这个接收网路应用程序定义数字标识,方便于明确哪些数据过来该应用程序可以处理。)。
    3. 建立数据包。
    4. 调用Socket发送接收方法。
    5. 关闭Socket。

二,代码练习:

 1 import java.net.DatagramPacket;
 2 import java.net.DatagramSocket;
 3 
 4 public class UdpRece {
 5             public static void main(String[] args) throws Exception{
 6                             
 7                             //定义接受端套接字
 8                             DatagramSocket ds = new DatagramSocket(10000);
 9                             
10                             //定义字节数组,保存接受内瓤
11                             byte buf[] = new byte[1024];
12                             
13                             //定义数据包,接受数据
14                             DatagramPacket dp = new DatagramPacket(buf,buf.length);
15                             
16                             //接受数据
17                             ds.receive(dp);
18                             
19                             //将字节构造成字符
20                             String revece = new String(buf);
21                             
22                             //标记发送端的端口
23                             int port = dp.getPort();
24                             
25                             //标记发送端的地址
26                             String address =dp.getAddress().getHostAddress();
27                             
28                             //输出内容
29                             System.out.println("address:"+address+"port"+port+"revece"+revece);
30                             
31             }
32 }

第九讲:网络编程(UDP-键盘录入方式数据)

一,一个特殊的IP地址: 192.168.1.255   广播地址。

二代码练习:

 1 import java.net.*;
 2 import java.io.*;
 3 
 4 
 5 public class UpdSend2 {
 6              public static void main(String[] args) throws Exception {
 7                          
 8                              //创建套接字对象
 9                              DatagramSocket ds = new DatagramSocket();
10                              
11                              //创建数组接收对象
12                              byte b[] = new byte[1024];
13                              
14                              //接受键盘输入
15                              System.in.read(b);
16                              
17                              //构建数据包
18                              DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("127.0.0.1"),10001);
19                              
20                              //发送数据包
21                              ds.send(dp);
22                              
23                              //关闭资源
24                              ds.close();
25             }
26 }

第十讲:网络编程(UDP-聊天)

 一,需求分析:

    编写一个聊天程序 有收数据的部分,和发数据的部分 这两部分需要同时执行 那就需要用到多线程技术 一个线程控制收,一个线程控制发

二,思路分析:

  1. 接收端和发送端需要同时完成收发功能。
  2. 接受数据,发送数据应当封装到两个线程中。

三,代码练习:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 
 5 //创建线程类,此类启动一个线程,执行在端口10001接受网络数据操作
 6 class MyRece implements Runnable{
 7     
 8     //覆盖run()方法
 9     @Override
10     public void run(){
11         
12         //循环接受数据
13         while (true){
14            try {
15                
16                //创建套接字对象,在端口10001接受网络数据
17                 DatagramSocket ds = new DatagramSocket(10001);
18             
19                 //存储接受内容
20                 byte b[] = new byte[1024];
21             
22                 //创建数据包对象
23                 DatagramPacket dp = new DatagramPacket(b,b.length);
24             
25                 //接受数据
26                 ds.receive(dp);
27                 
28                 //打印接受到的数据
29                 System.out.println("主机:"+dp.getAddress()+"发来:"+new String(dp.getData(),0,dp.getLength()));
30                 
31                 //判断是否关闭程序
32                 if(dp.getData().toString().trim().equals("886"))
33                     //当对放发送886程序结束
34                     break;
35             } catch (SocketException e) {
36                 System.out.println("网络错误"+e.toString());
37             }catch (IOException e){
38                  System.out.println("IO错误"+e.toString());
39             } 
40             
41         }
42     }
43 }
44 
45 
46 //创建一个类启动一个线程,该线程实现发送用户从键盘输入的内容
47 class MySend implements Runnable{
48     
49         //覆盖方法
50         @Override
51         public void run(){
52             //循环接受发送
53             while(true){
54                 
55                 try{
56                     //创建套接字对象
57                      DatagramSocket ds = new DatagramSocket();
58                     
59                     //创建缓冲输入流,从键盘接受数据
60                     BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
61                     
62                     //存储键盘输入的一行数据
63                     String line = null;
64                     
65                     //如果用户输入886 ,发送数据,并结束程序运行
66                     if((line=br.readLine()).trim().equals("886")){
67                         DatagramPacket dp = new DatagramPacket(line.getBytes(),line.getBytes().length,InetAddress.getByName("127.0.0.1"),10001);
68                         
69                         ds.send(dp);
70                         break;
71                     }
72                     
73                     //发送数据
74                     DatagramPacket dp = new DatagramPacket(line.getBytes(),line.getBytes().length,InetAddress.getByName("127.0.0.1"),10001);
75                     
76                     ds.send(dp);
77                         
78                 }catch(IOException e){
79                     System.out.println("IO异常"+e.toString());
80                 } 
81                 
82             }
83         }
84 }
85 public class ChatDemo {
86                 public static void main(String[] args) {
87                     
88                     
89                        //创建线程对象
90                        Thread t1 = new Thread(new MyRece());
91                        Thread t2 = new Thread(new MySend());
92                        
93                        //启动线程
94                        t1.start();
95                        t2.start();
96                 }
97 }

第十一讲:网络编程(TCP传输)

一,TCP传输过程。

    1. 建立,Socket(客户端) 和ServerSocket(服务端,服务端需要明确它要处理的数据是从哪个端口进入的。)。=====因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在,并连接成功,形成通路后,再通过该通道进行数据的传输。===
    2. 通过Socket中的IO流进行数据的传输。
    3. 关闭Socket。
    4. 客户端和服务器端是两个独立的应用程序。

二,涉及道的类了解:

  1. Socket: 
    1. 定义:public class Socket extends Object    此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
    2. 构造方法:public Socket()          通过系统默认类型的 SocketImpl 创建未连接套接字                ==注:创建空参数的客户端对象,一般用于服务端接收数据==
    3. 构造方法:public Socket(String host, int port) throws UnknownHostException, IOException     创建一个流套接字并将其连接到指定主机上的指定端口号。
    4. 方法:public void bind(SocketAddress bindpoint) throws IOException    将套接字绑定到本地地址。如果地址为 null,则系统将挑选一个临时端口和一个有效本地地址来绑定套接字。
    5. 方法:public InetAddress getInetAddress()     返回套接字连接的地址。
    6. 方法:public int getPort()                               返回此套接字连接到的远程端口。
    7. 方法:public InetAddress getLocalAddress()   获取套接字绑定的本地地址。
    8. 方法:public int getLocalPort()                      返回此套接字绑定到的本地端口。
    9. 方法:public InputStream getInputStream() throws IOException  返回此套接字的输入流。
    10. 方法:public OutputStream getOutputStream() throws IOException   返回此套接字的输出流。
  2. ServerSocket:
    1. 类的定义:public class ServerSocket extends Object    此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
    2. 构造方法:public ServerSocket() throws IOException   创建非绑定服务器套接字。
    3. 构造方法:public ServerSocket(int port) throws IOException   创建绑定到特定端口的服务器套接字。
    4. 方法:public Socket accept() throws IOException    侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
    5. 方法:public void bind(SocketAddress endpoint) throws IOException   将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
    6. 方法:public InetAddress getInetAddress()         返回此服务器套接字的本地地址。将此套接字绑定到的地址;如果套接字是未绑定的,则返回 null
    7. 方法:public int getLocalPort()                           返回此套接字在其上侦听的端口。此套接字侦听的端口号;如果尚未绑定套接字,则返回 -1。

三,思路分析:

客户端:

        通过查阅Socket对象的API文档,发现在该对象在建立时,就可去连接指定主机,因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在,并连接成功,形成通路后,再通过该通道进行数据的传输。

         1)创建Socket服务,并指定要连接的主机端口。通路一建立,就会产生Socket流(包括输入流和输出流),通过方法获取。========注:如果连接失败,会出现异常。连接成功,说明客户端与服务端建立了通道,之后即可以通过IO流交换数据。==========

         2)为了发送数据,应获取Socket中的输出流,如果要接收服务端的反馈信息,还需要获取Socket的输入流

         3)通过输出流的write()方法将要发送的数据写入到流中

         4)关闭Socket流资源

服务端:

        服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。需监听一个端口。

         1)建立服务端的Socket服务,并监听一个端口。通过ServerSocet带端口参数的构造函数

         2)获取连接过来的客户对象,通过ServerSocket的accept()方法,此方法是阻塞式的,如果服务端没有连接到就会一直等待

         3)客户端如果发过来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过来的数据,并输出到指定目的地。当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。

         4)关闭服务端(可选)。一般服务端是常开的,因为在实际应用中,随时有客户端在请求连接和服务。但这里需要定时关闭客户端对象流,避免某一个客户端长时间占用服务器端。

四,代码练习:

服务器端:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 
 5 //创建TCP服务器端,接受消息
 6 public class TCPServ {
 7                 public static void main(String[] args) {
 8                             
 9                         try {
10                             
11                             //创建服务器端套接字,在指定端口监听
12                             ServerSocket ss = new ServerSocket(20000);
13                             
14                             //获得接收到的套接字的输入流
15                             InputStream is = ss.accept().getInputStream();
16                             
17                             //存储数据
18                             byte b[] = new byte[1024];
19                             
20                             //读入数据
21                             is.read(b);
22                             s.close();
23                             //打印
24                             System.out.println(new String(b,0,b.length));
25                             
26                         } catch (IOException e) {
27                             // TODO Auto-generated catch block
28                             e.printStackTrace();
29                         } 
30                 }
31 }

客户端:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 
 5 //创建客户端,以TCP方式连接到远程服务器
 6 class TCPClient {
 7             public static void main(String[] args) {
 8                 
 9                 
10                 try {
11                     
12                     //创建客户端套接字,连接到制定主机的20000端口上
13                     Socket s = new Socket(InetAddress.getByName("202.206.154.123"), 20000);
14                     
15                     //获得到远端主机的输出流
16                     OutputStream out = s.getOutputStream();
17                     
18                     //输出数据
19                     out.write("您好".getBytes());
20                     //关闭资源
21                     s.close();
22                 } catch (UnknownHostException e) {
23                     System.out.println("为找到主机"+e.toString());
24                 } catch (IOException e) {
25                     System.out.println("IO异常"+e.toString());
26                 }
27             }
28 }

第十二讲:网络编程(TCP传输2)

一,练习:需求分析:客户端给服务端发送数据,服务端收到后,给客户端反馈信息

二,代码练习:

客户端:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 
 5 //创建客户端,以TCP方式连接到远程服务器
 6 class TCPClient {
 7             public static void main(String[] args) {
 8                 
 9                 
10                 try {
11                     
12                     //创建客户端套接字,连接到制定主机的20000端口上
13                     Socket s = new Socket(InetAddress.getByName("202.206.154.123"), 20000);
14                     
15                     //获得到远端主机的输出流
16                     OutputStream out = s.getOutputStream();
17                     
18                     //输出数据
19                     out.write("您好".getBytes());
20                     
21                     
22                     //接受服务端消息
23                     byte b[] = new byte[1024];
24                     
25                     //获取输入流
26                     InputStream in = s.getInputStream();
27                     
28                     //标记接受数据量
29                     int len=0;
30                     
31                     //读入数据
32                     len=in.read(b);
33                     
34                     //输出数据
35                     System.out.println(new String(b,0,len));
36                     //关闭资源
37                     s.close();
38                 } catch (UnknownHostException e) {
39                     System.out.println("为找到主机"+e.toString());
40                 } catch (IOException e) {
41                     System.out.println("IO异常"+e.toString());
42                 }
43             }
44 }

服务器端:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 
 5 //创建TCP服务器端,接受消息
 6 public class TCPServ {
 7                 public static void main(String[] args) {
 8                             
 9                         try {
10                             
11                             //创建服务器端套接字,在指定端口监听
12                             ServerSocket ss = new ServerSocket(20000);
13                             
14                             Socket s = ss.accept();
15                             //获得接收到的套接字的输入流
16                             InputStream is = s.getInputStream();
17                             
18                             //存储数据
19                             byte b[] = new byte[1024];
20                             
21                             //读入数据
22                             is.read(b);
23                             
24                             //打印
25                             System.out.println(new String(b,0,b.length));
26                             
27                             //获取输出流
28                             OutputStream out = s.getOutputStream();
29                             
30                             //向客户端写入数据
31                             out.write("客户端你也好".getBytes());
32                             
33                             //关闭资源
34                             s.close();
35                             
36                         } catch (IOException e) {
37                             // TODO Auto-generated catch block
38                             e.printStackTrace();
39                         } 
40                 }
41 }

第一十三讲:网络编程(TCP练习)

一,需求分析:

                建立一个文本转换服务器, 客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端 ,而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束 。

二,操作步骤:

    1. 建立服务。
    2. 获取键盘输入。
    3. 将数据发给服务端。
    4. 接受服务端返回的数据。
    5. 关闭资源。

==============特别注意:如果使用字符缓冲区,写入完毕后,需要加入换行和刷新====================

三,代码练习:

 客户端:

 1 import java.net.*;
 2 import java.io.*;
 3 public class TCPClient {
 4                 public static void main(String[] args) {
 5                             
 6                             //创建套接字连接服务器
 7                             Socket s = null;
 8                             
 9                             //获取输出流
10                             OutputStream out = null;
11                             
12                             //获取输入流
13                             InputStream is = null;
14                             
15                             
16                             try {
17                                 s = new Socket(InetAddress.getByName("127.0.0.1"),10000);
18                                 
19                                 out = s.getOutputStream();
20                                 
21                                 is = s.getInputStream();
22                             } catch (UnknownHostException e) {
23                                 // TODO Auto-generated catch block
24                                 e.printStackTrace();
25                             } catch (IOException e) {
26                                 // TODO Auto-generated catch block
27                                 e.printStackTrace();
28                             }
29                             
30                              
31                             
32                             //字符缓冲流增加效率
33                             BufferedReader brr = new BufferedReader(new InputStreamReader(is));
34                             
35                             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
36                             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
37                             
38                             try{
39                             //循环发送数据接收数据
40                             while(true){
41                                 
42                                 //接收读入内容
43                                  String line = null;
44                                  
45                                  //读入数据
46                                  line = br.readLine();
47                                  
48                                  //写出数据
49                                  bw.write(line);
50                                  
51                                  //换行
52                                  bw.newLine();
53                                  
54                                  //刷新
55                                  bw.flush();
56                                  
57                                  if("over".equals(line))
58                                      break;
59                                  line=brr.readLine();
60                                 
61                                  System.out.println(line);
62                             }
63                             s.close();
64                             }catch (Exception e){
65                                 System.out.println(e.toString());
66                             }
67                 }
68 }            

服务器端:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 public class TCPServ {
 5             public static void main(String[] args)   {
 6                 
 7                         //创建服务器端套接字,在端口10000监听
 8                         ServerSocket ss = null;
 9                         
10                         //获取与客户端关联的 Socket
11                         Socket s = null;
12                         
13                         //获取到客户端的输入流
14                         InputStream is = null;
15                         
16                         OutputStream out =null;
17                         
18                         try {
19                             ss = new ServerSocket(10000);
20                             
21                             s = ss.accept();
22                             
23                             out = s.getOutputStream();
24                             is = s.getInputStream();
25                         } catch (IOException e) {
26                             // TODO Auto-generated catch block
27                             e.printStackTrace();
28                         }
29                         
30                         
31                         
32                         
33                         
34                         //使用字符缓冲流提高效率
35                         BufferedReader br = new BufferedReader(new InputStreamReader(is));
36                         
37                         //字符缓冲流
38                         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
39                         
40                         
41                     try{
42                         //循环接受客户端消息
43                         while(true){
44                             
45                             //接受客户端内容
46                             String line = null;
47                             
48                             //读入数据
49                             line = br.readLine();
50                             
51                             //判断是否结束
52                             if("over".equals(line))
53                                 break;
54                             
55                             //向客户端写入数据
56                             bw.write(line.toUpperCase());
57                             
58                             //换行
59                             bw.newLine();
60                             
61                             //刷新
62                             bw.flush();
63                         }
64                         ss.close();
65                     }catch(Exception e){
66                         System.out.println(e.toString());
67                     }
68             }
69 }

第一十四讲:网络编程(TCP复制文件)

一,注意的问题:

    1. 因为客户端将数据发送完毕后,服务端仍然在等待这读取数据,并没有收到结束标记,就会一直等待读取。 
    2. 上个问题解决后,收到的不是指定信息而是null,是因为服务端写入数据后,需要刷新,才能将信息反馈给客服端。

二,解决办法:

    1. 定义结束标记,先将结束标记发送给服务端,让服务端接收到结束标记,然后再发送上传的数据。但是这样定义可能会发生定义的标记和文件中的数据重复,而导致提前结束。
    2. 定义时间戳,由于时间是唯一的,在发送数据前,先获取时间,发送完后在结尾处写上相同的时间戳,在服务端,接收数据前先接收一个时间戳,然后在循环中判断时间戳以结束标记。
    3. 通过socket方法中的shutdownOutput(),关闭输入流资源,从而结束传输流,以给定结束标记。通常用这个方法。 

三,代码练习

客户端软件:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 public class TextClient {
 5                 public static void main(String[] args) {
 6                                 
 7                     
 8                                 //创建客户端套接字
 9                                 Socket s = null;
10                                 
11                                 //输出流,输入流对象声明
12                                 InputStream is = null;
13                                 
14                                 OutputStream os = null;
15                                 
16                                 FileInputStream fis = null;
17                                 
18                                 //标识文件
19                                 String filename = "E:/sysinfo.txt";
20                                 
21                                 File file = new File(filename);
22                                 
23                                 
24                                 //实例化对象引用
25                                 try{
26                                     s = new Socket(InetAddress.getLocalHost(),10000);
27                                     
28                                     is = s.getInputStream();
29                                     
30                                     os = s.getOutputStream();
31                                     
32                                     
33                                     //判断文件是否存在
34                                     if(!file.exists())
35                                         System.out.println("文件不存在");
36                                     else {
37                                         fis = new FileInputStream(file);
38                                     }
39                                 }catch(Exception e){
40                                     System.out.println(e.toString());
41                                 }
42                                 
43                                 
44                                 //字符缓冲刘提高操作效率
45                                 BufferedReader br_file = new BufferedReader(new InputStreamReader(fis));
46                                 BufferedReader br_net = new BufferedReader(new InputStreamReader(is));
47                                 
48                                 //获得服务端输出流
49                                 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
50                                 
51                                 try{
52                                     String line = null;
53                                     
54                                     //循环读取文件并发送到服务器端
55                                     while ((line=br_file.readLine())!=null){
56                                         
57                                         //写入一行字符
58                                         bw.write(line);
59                                         
60                                         //写入换行符
61                                         bw.newLine();
62                                         
63                                         //刷新输出流
64                                         bw.flush();
65                                     }
66                                     
67                                     //写入结束标志
68                                     bw.write("end");
69                                     bw.newLine();
70                                     bw.flush();
71                                     
72                                     //获取服务端响应
73                                     line = br_net.readLine();
74                                     
75                                     System.out.println(line);
76                                 }catch(IOException e){
77                                     System.out.println(e.toString());
78                                 }
79                 }
80 }

 

服务端代码:

 

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 public class TextServ {
 5                 public static void main(String[] args) {
 6                             
 7                             //创建服务端套接字
 8                             ServerSocket ss = null;
 9                             
10                             //接受客户端
11                             Socket s = null;
12                             
13                             ////客户端输入流
14                             InputStream is = null;
15                             
16                             //客户端输出流
17                             OutputStream os = null;
18                             
19                             //定义文件
20                             File file = new File("E:/rever.txt");
21                             
22                             //定义文件输入流
23                             FileOutputStream fos = null;
24                             
25                             //实例化对象
26                             try{
27                                 ss = new ServerSocket(10000);
28                                 
29                                 s = ss.accept();
30                                 
31                                 is = s.getInputStream();
32                                 
33                                 os = s.getOutputStream();
34                                 
35                                 fos = new FileOutputStream(file);
36                             }catch(Exception e){
37                                 System.out.println(e.toString());
38                             }
39                             
40                             //字符缓冲刘提高效率
41                             BufferedReader br = new BufferedReader(new InputStreamReader(is));
42                             
43                             //缓冲输出流。提高效率
44                             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
45                             
46                             
47                             BufferedWriter bw_file = new BufferedWriter(new OutputStreamWriter(fos));
48                             
49                             //异常处理
50                             try{
51                                 
52                                 //接受读入一行字符串
53                                 String line = null;
54                                 
55                                 //循环读取
56                                 while((line=br.readLine())!=null){
57                                     //判断是否结束
58                                     if("end".equals(line))
59                                         break;
60                                     
61                                     //保存到本地文件
62                                       bw_file.write(line);
63                                       
64                                       //写入换行符
65                                       bw_file.newLine();
66                                       
67                                       //刷新输出流
68                                       bw_file.flush();
69                                 }
70                                 
71                                 //给出提示
72                                 bw.write("写入成功");
73                                 
74                                 //写入换行符
75                                   bw.newLine();
76                                   
77                                   //刷新
78                                   bw.flush();
79                             }catch(Exception e){
80                                 System.out.println(e.toString());
81                             }
82                             
83                 }
84 }

 

 

 
原文地址:https://www.cnblogs.com/xiaochongbojue/p/4055211.html