• 黑马程序员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 引用的资源

  • 相关阅读:
    CSS基础
    HTML基础
    JavaScript基础目录
    python 面向对象的基本概念(未完待续)
    python核心编程笔记(转)
    转: cJSON的使用方法
    转: C语言交换两个变量数值的几种方法
    转: 100个gdb小技巧项目
    转:C语言中的typeof关键字
    转:安全起见,小心使用C语言realloc()函数
  • 原文地址:https://www.cnblogs.com/jbelial/p/3104323.html
Copyright © 2020-2023  润新知