黑马程序员-Java基础-网络编程

   Java 为网络编成提供了java.net 包。Java支持TCP/UDP 及其上层的网络编程。、

一、网络程序设计基础

  1、TCP和UDP

  TCP(Transmission Control Protocol,传输控制协议)是面向连接的传输层协议。即应用进程在使用TCP协议之前,必须建立TCP连接,在传输完毕后,释放已经建立的连接。利用TCP协议进行

通信的两个应用进程:

  1、是服务器进程。

  2、客户端进程。

  UDP(User Datagram Protocol,用户数据报协议)是面向无连接的传输层协议,即应用进程在使用UDP协议之前,不必先建立连接。

  2、端口和套接字

  端口也称为协议端口。端口用一个整数型标识符来表示,即端口号。端口号跟协议相关,TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号保留给预定义的服务,

他的范围是0~655535。

  端口好拼接到IP 地址即构成套接字(Socket)。 在客户/服务器通信模式中,客户端需要主动创建与服务器连接的Socket,服务器进程接收到了客户端的连接请求时,也会创建与客户连接的Socket。Socket可看做是通信连接两端的收发器,服务器进程与客户进程都通过Socket来收发数据。在一个Socket 对象中同时包含了远程服务器的IP地址和端口信息,以及本地客户的IP 地址和端口信息。从Sokcet对象中还可以获得输入输出流,分别用于接收从服务器端发来的数据,以及向服务器发送数据。

 

二、UDP网络编程

  在Java中,java.net.DatagramSocket 负责接收和发送UDP 数据报 ,而java.net.DatagramPacket 表示UDP数据报。

  每个DatagramSocket 与一个数据报套接字绑定,每个DatagramSocket 可以把UDP数据报发送给任意一个远程DatagramSocket,也可以接收来自任意一个远程DatagramSocket 的数据报,

在UDP 数据报中包含了目的信息,DatagramSocket 可以根据该信息把数据发送到目的地。

  DatagramSocket 类常用的方法:

  > void send(DatagramPacket p ) throws IOException :发送一个UDP 数据报。

  > void receive(DatagramPacket p ) throws IOException : 接收一个UDP 数据报。

  > void connect(InetAddress addr, int post) :将该UDPSocket 变成一个连接型的UDPSocket 。

  > void disconnect( ) :将该UDPSocket 变成一个非连接型的UDPSocket 。

  > void close() :关闭该UDPSocket 。

   DatagramPacket 类的对象代表了一个UDP 数据报包,通过UDP 发送数据时,

    1、根据发送的数据生成一个DatagramPacket 对象。

    2、通过DatagramSocket 对象的send() 方法发送这个对象。

  接收数据包时:

    1、根据要接收数据的缓冲区生成一个DatagramPacket 对象。

    2、通过DatagramSocket 对象的receive() 方法接收这个对象的内容。

   所以,DatagramPacket 类的构造方法分为两类:

    1、创建DatagramPacket 对象用来发送数据报,如:

      DatagramPacket(byte[] buf, int length , InetAddress addr , int post) ,

    2、用于接收数据包构造方法,如:

      DatagramPacket(byte[] buf, int length) ;

   DatagramPacket 类的常用方法:

    > byte[] getData() : 返回DatagramPacket对象中包含的数据。

    > int getLength() : 返回发送/接收数据的长度。

  练习:通过UDP传输方式,客户程序向接收程序发送小写字符串,服务器程序接收到后,并将其转换成大写返回给客户程序。

  思路:
          服务程序 :
          1、建立UDPSocket服务,并监听一个端口。
          2、创建接收数据报对象。
          3、接收到数据报,并将数据类容转换成大写。
          4、将转换完的内容发送给客户程序。
          5、关闭资源。

 1 public class UDPServer {
 2     public static void main(String[] args) throws  Exception {
 3 //        定义服务端Socket , 端口号为 10001
 4         DatagramSocket ds = new DatagramSocket(10001) ;
 5         while(true) {
 6 //            创建接收数据包
 7             byte[] buf = new byte[1024] ; 
 8             DatagramPacket r_dp = new DatagramPacket(buf,buf.length) ; 
 9             ds.receive(r_dp) ;
10 //            取出发送端的IP地址和端口,
11             InetAddress  addr = r_dp.getAddress() ; 
12             int post = r_dp.getPort() ; 
13 //            客户端发送的数据:
14             String str = new String(buf,0,r_dp.getLength()) ;
15             System.out.println("IP:"+addr+",post:"+post
16                     +":"+ str);
17             
18 //            将转换的完的内容发送个客户程序
19             buf = str.toUpperCase().getBytes();
20             DatagramPacket s_dp = new DatagramPacket(buf
21                     , buf.length, addr , post) ;
22             ds.send(s_dp) ;
23         } 
24     }
25 }

 

     客户程序:          

    1、建立UDPSocket服务,并监听一个端口。          

    2、提供数据。并将数据封装到数据包。

    3、通过Socket服务的发送功能,将数据包发出去。          

    4、接收服务端发送的数据。          

    5、关闭资源。

 1 public class UDPClient {
 2     public static void main(String[] args) throws  Exception {
 3         DatagramSocket ds = new DatagramSocket() ;
 4         
 5         BufferedReader bufr =
 6             new BufferedReader(new InputStreamReader(System.in)) ;
 7         
 8         String line = null ; 
 9         InetAddress address = InetAddress.getByName("127.0.0.1") ;
10         byte[] buf = new byte[1024] ;
11         while ((line = bufr.readLine()) != null) {
12             if ("exit".equals(line))
13                 break ;
14             
15             buf = line.getBytes() ; 
16             DatagramPacket s_dp = 
17                 new DatagramPacket(buf, buf.length, address ,10001) ; 
18             ds.send(s_dp) ;
19             
20 //            接收数据包
21             DatagramPacket r_dp = new DatagramPacket(buf, buf.length) ;
22             ds.receive(r_dp) ;
23             System.out.println(new String(buf,0,r_dp.getLength()));
24         }
25         ds.close() ;
26     }
27 }

  总结:对于网络编程知识,首先要有清晰的功能流程思路,这样编写起来会非常上手。

  

三、TCP网络编程

    Java 的基于套接字编程分为服务端编程和客户端编程:

  服务器编程:

  1、调用ServerSocket(int port) 创建一个服务器套接字,并绑定到指定端口上。

  2、调用accept(),监听连接请求,如果客户端请求连接,并接收连接,返回客户端套接字Scoket。

  3、调用Socket 类的getOutputStream 和getInputStream 获取网络输出和输入流,开始网络数据的发送和接收。

  4、关闭通信套接字。

  客户端编程:

  1、调用Socket()创建一个流套接字,并请求连接到服务器。

  2、调用Socket 类的getOutputStream 和getInputStream 获取网络输出和输入流,开始网络数据的发送和接收。

  3、关闭通信套接字。

  练习:模拟一个文件上传的C/S 程序。即可以多个用户同时向客户端上传mp3格式文件。

  分析:在多个客户端同时连接服务器,并对服务器进行上传文件操作时,则需要使用多线程,否则会出现局限性:当一个客户端连接服务器时,其他客户端则不能连接上。

    问:如何定义线程?

  明确每个客户端要在服务端执行的代码,将该代码存入run方法中。如:

  服务器:

  1、创建服务器Socket 。

  2、接收客户端连接。

  3、接收客户端上传的文件。

  4、接收完成,返回信息。

  5、关闭资源。

   上面5个步骤中,3、4则是客户端要在服务端执行的代码,我们则将该代码存入run()方法中。

  服务端代码:

 1 import java.io.*; 
 2 import java.net.*;
 3 public class TCPServer{
 4     public static void main(String[] args) throws Exception {
 5 //        创建服务器socket 
 6         ServerSocket server = new ServerSocket(10000) ; 
 7         while(true) {
 8 //            接收客户端连接
 9             Socket client = server.accept() ; 
10 //            有客户端连接,便创建线程
11             new Thread(new TCPFileToServer(client)).start() ;
12         }
13     }
14 }
15 class TCPFileToServer implements Runnable{
16     private Socket client ;
17     TCPFileToServer(Socket client){
18         this.client = client ;
19     }
20     public void run(){
21         int count = 1 ;
22         try{
23 //            定义存储文件的名字。
24             String ip = client.getInetAddress().getHostAddress() ;
25             File file = new File("f:\\"+ip+"("+(count++)+")"+".mp3") ;
26             
27             while(file.exists())
28                 file = new File("f:\\"+ip+"("+(count++)+")"+".mp3") ;
29 //            收取文件
30 //            文件输出流:
31             BufferedWriter bufw = 
32                 new BufferedWriter(
33                         new OutputStreamWriter(
34                                 new FileOutputStream(file))) ; 
35 //            网络输入流:
36             BufferedReader bufr = 
37                 new BufferedReader(
38                         new InputStreamReader(client.getInputStream()));
39             String line = null ; 
40             while ((line = bufr.readLine())!= null) {
41                 bufw.write(line) ;
42             }
43 //            网络输出流:
44             PrintWriter out = new PrintWriter (client.getOutputStream(),true) ;
45             out.println("上传成功!") ;
46 //            关闭资源。
47             bufw.close();
48             client.close() ; 
49         }    
50         catch(Exception e){
51             new RuntimeException("上传失败。") ;
52         }
53     }
54 }

  客户端代码如:

 1 import java.net.*;
 2 import java.io.*; 
 3 public class TCPFileClient {
 4     public static void main(String[] args) throws Exception{
 5 //        创建客户端Socket
 6         Socket client = new Socket(InetAddress.getByName("127.0.0.1"),10000) ;
 7         if (args.length != 1)
 8             return ;
 9 //        输出要上传文件的地址
10         File file = new File(args[0]) ; 
11         
12 //        网络输出流
13         PrintWriter out = 
14             new PrintWriter(
15                     client.getOutputStream(),true);
16 //        文件读取流
17         BufferedReader bufr = 
18             new BufferedReader(
19                     new InputStreamReader(
20                             new FileInputStream(file))) ;
21         String line = null ; 
22         while ((line = bufr.readLine())!=null) {
23             out.println(line) ;
24         }
25         client.shutdownOutput() ;
26 //        网络输入流
27         byte[] buf = new  byte[1024] ; 
28         InputStream in =  client.getInputStream();
29         int len = in.read(buf) ; 
30         System.out.println(new String(buf,0,len));
31 //        关闭资源
32         bufr.close() ;
33         client.close() ;
34     }
35 }

  练习2:客户端并发登录:客户端通过键盘录入登录用户名。服务端对这个用户名进行校验。

  如果该用户存在,在服务端显示xxx,已经登录。

  并在客户端显示,xxx,欢迎登录。

  如果该用户不存在,在服务端显示xxx,尝试登录。

  并在客户端显示,xxx,该用户不存在。(在用户错误的情况下不能连续登录3次以上)

  思路:

  客户端:
     1、创建Socket 服务,连接服务器。
     2、键入用户名,并发送给服务器。
     3、收到返回的信息。
     4、关闭资源。

 1 import java.io.*;
 2 import java.net.*;
 3 public class LoginClient {
 4     public static void main(String[] args) throws Exception {
 5 //        创建客户端Socket
 6         Socket client = new Socket("127.0.0.1", 10000) ;
 7         
 8 //        输入用户名端。
 9         BufferedReader bufr = 
10             new BufferedReader(new InputStreamReader(System.in)) ;
11 //        网络输出流
12         PrintWriter pw = 
13             new PrintWriter(client.getOutputStream(),true) ;
14 //        网络输入流
15         BufferedReader br = 
16             new BufferedReader(new InputStreamReader(client.getInputStream())) ;
17 //        键入用户名
18         for (int i = 0 ; i < 3 ; i ++) {
19             String line = bufr.readLine() ;
20             if(line == null) 
21                 break ; 
22             pw.println(line) ;
23 //            接收信息
24             String info = br.readLine() ;
25             System.out.println(line+","+info);
26             if(info.contains("欢迎"))
27                 break ;
28         }
29     }
30 }

  服务器:
    思路:
    1、建立服务器Socket.
    2、接收客户端连接。
    3、创建客户端线程。
       3.1、判断用户名是否合法。
       3.2、判断用户是否存在。
    4、关闭资源。

 1 import java.net.*; 
 2 import java.io.*;
 3 public class LoginServer {
 4     public static void main(String[] args) throws  Exception {
 5         ServerSocket server = new ServerSocket(10000) ; 
 6         while (true) {
 7             Socket client = server.accept() ; 
 8             new Thread(new ClientThread(client)).start() ;
 9         } 
10     }
11 }
12 
13 class ClientThread implements Runnable {
14     private Socket  client ;
15     public ClientThread(Socket client) {
16         this.client = client ; 
17     }
18     public void run() {
19         try {
20             for (int i = 0 ; i < 3 ; i ++) { 
21 //                文件输入流:读取用户信息
22                 BufferedReader bufr = 
23                     new BufferedReader(new FileReader("F:\\user.txt")) ; 
24 //                    网络输入流

25                 BufferedReader br = 
26                 new BufferedReader(new InputStreamReader(client.getInputStream())) ;
27 //                网络输出流
28                 PrintWriter pw = 
29                 new PrintWriter(client.getOutputStream(),true) ;
30                 String name = br.readLine() ;
31                 if (name == null)
32                     break ;
33                 String line = null ;
34                 boolean flag = false ;
35                 while ((line = bufr.readLine()) != null) {
36                     if ( line.equals(name) ) {
37                         flag = true ;
38                         break ;
39                     }
40                 }
41                 if (flag) {
42                     System.out.println(name + ",已经登录");
43                     pw.println("欢迎登录.") ;
44                 }
45                 else {
46                     System.out.println(name + ",尝试登录。");
47                     pw.println("用户不存在.") ;
48                 }
49             } 
50             client.close() ;
51         }
52         catch(Exception e) {
53             
54         }
55     }
56 }

  

四、URL

  URL(Uniform Resurse Locator ,统一资源定位器),用来表示从英特网上得到资源位置和访问位置这些资源的方法。协议名://资源名

  如:http://www.cnblogs.com/jbelial/

  其中:协议名是http 协议,主机名是www.cnblogs.com,端口默认80,文件路径名是/jbelial/。

  1、URL类

  URL 类代表了一个同一资源定位符,它是指向互联网资源的指针。

  URL 类的构造方法如下:

  > URL(String spec ) :由一个表示URL 地址的字符串构造一个URL对象。

  > URL(String protocol , String host , int port , String file) :根据指定protocol、host、port号和file创建URL 对象。

  常用方法:

  > InputStream openStream() :打开一个连接到该URL 的InputStream 的对象,通过对象,可以URL 中读取Web 页面内容。

  > URLConnection openConnection() :创建并返回一个 URLConnection 对象,它表示到URL所引用的远程对象的连接。

  > Object getContent() : 获取此URL 的内容。

  > String getFile() :获取次URL的文件名。

  > String getHost(): 获取次URL的主机名

  > String getPath(): 获取次URL的路径部分。

  > String getProtocol(): 获取次URL的协议名称

  > String getQuery(): 获取次URL 的查询。

 1 public class TomcatDemo {
 2     public static void main(String[] args) throws Exception {
 3         if(args.length != 1)
 4             return ;
 5 //        创建一个URL 对象
 6         URL url = new URL(args[0]) ; 
 7 //        缓冲流
 8         BufferedReader bufr = new BufferedReader(new InputStreamReader(url.openStream())) ;
 9         String line = null ; 
10         while ((line = bufr.readLine()) != null) {
11             System.out.println(line);
12         }
13         bufr.close() ;
14     }
15 }

  运行时输入:http://jbelial.cnblogs.com 则可以获取到该URL的内容。

  2、URLConnection 类

  抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源

 

 

 

 

 

 

posted @ 2013-05-29 13:55  贺佐安  阅读(471)  评论(0编辑  收藏  举报