zoukankan      html  css  js  c++  java
  • 黑马程序员----java基础--网络编程

    ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

    一、  网络参考模型 

    1、OSI参考模型和 TCP/IP 参考模型

    七层描述:

    (1). 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流。

    (2). 数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。这一层工作的设备是交换机,数据通过交换机来传输。

    (3). 网络层:主要将下层接收到的数据进行IP地址(例,192.168.0.1)的封装与解封装。这一层工作的设备是路由器。。

    (4). 传输层:定义了一些传输数据的协议和端口号(WWW端口号80等),主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。

    (5). 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接收会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。

    (6). 表示层:主要是进行对接收的数据进行解释,加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够识别的东西(如图片、声音等)。

    (7). 应用层:主要是一些终端的应用,比如说FTP(各种文件下载)、WEB(IE浏览)、QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西,就是终端应用)。

    注:

    (1).每个网卡的MAC地址都是全球唯一的。

    (2).路由器实现将数据包发送到指定的地点。

    (3).应用软件之间通信的过程就是层与层之间封包、解包的过程

    (4).OSI参考模型虽然设计精细,但过于麻烦,效率不高,因此才产生了简化版的TCP/IP参考模型。

    2、网络通信三要素:IP地址,端口号,传输协议。

    (1)、IP地址:InetAdderss类

    1.它是网络中的设备标识

    2.不易记忆,可用主机名表示,两者存在映射关系

    3.IPV4数量已经不够分配,所以产生了IPV6

    4.本地回环地址:127.0.0.1 主机名:localhost

    5.在没有连接互联网的情况,为了让访问本机方便,所以分配了一个默认的IP地址,也就是本地回环地址

    (2)、端口号

    1.用于标识进程(应用程序)的逻辑地址,不同进程的标识

    2.有效端口:0~65535,其中0~1024系统使用或保留端口。

    3.没有程序都有端口号用来定为应用程序

    (3)、传输协议 

    这是通讯的规则。常见协议有:UDP、TCP。

    UDP

    1.将数据以及源和目的封装成数据包中,不需要建立连接

    2.每个数据包的大小限制在64k内

    3.因无连接,所以是不可靠的协议

    4.不需要建立连接,速度快

    应用案例:QQ聊天、视频聊天、对讲机、FeiQ、视频教学等在线视频都是UDP

    TCP

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

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

    3.通过三次握手完成连接,是可靠协议。三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方确认对方连接成功。

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

    应用案例:FTP文件传输、迅雷下载、打电话

    3、java.net.InetAdderss常用网络方法

    无构造函数,只能用方法返回本类对象

    1 static  InetAddress    getLocalHost();//返回一个InetAdderss本类对象
    2 static  String    getHostName();//返回此ip地址的主机名
    3 static   String    getHostAddress();//返回ip地址字符串
    4 String    toString();//返回此ip地址的String表现形式
    5 static    InetAddress    getByName(String host);//获取指定主机名的ip地址
    6 static  InetAddress[]    getAllByName(String host);//获取指定主机名的全部ip地址

     代码演示:

     1 import java.net.*;
     2 class InetAddressDemo 
     3 {
     4     public static void main(String[] args) throws Exception
     5     {
     6         InetAddress ia= InetAddress.getLocalHost();//返回InetAddress本来对象
     7         String name=ia.getHostName();//获取IP地址的主机名
     8         String ip=ia.getHostAddress();//获取本地ip地址
     9         System.out.println("name="+name);
    10         System.out.println("ip="+ip);
    11 
    12         InetAddress i=InetAddress.getByName("192.168.1.1");//获取指定主机的IP 地址
    13         System.out.println(i.getHostAddress());
    14 
    15         InetAddress[] ina=InetAddress.getAllByName("www.sina.com.cn");//获取指定主机名的全部ip地址
    16         for (InetAddress a:ina )
    17         {
    18             System.out.println(a.getHostAddress());
    19             System.out.println(a.getHostName());
    20         }
    21     }
    22 }

     二、UDP协议-发送端和接收端

    Socket:套接字,通信的端点。就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。

    1、DatagramSocket和DatagramPacket对象

     (1)、DatagramSocket类常用方法

    此类表示用来发送和接收数据报包的套接字。

    1、构造方法

    1 new    DatagramSocket();//构造数据报套接字并绑定到本地主机任何端口上,发送端
    2 new    DatagramSocket(int port);//创建数据报套接字并绑定到本地主机上的指定端口,接收端

     2、一般方法

    1 void    connect(InetAddress address,int port);//将套接字连接到此套接字的远程地址上
    2 void    send(DatagramPacket p);//从此套接字发送数据包
    3 void    receive(DatagramPacket p);//从此套接字接收数据包
    4 InetAddress    getInetAddress();//返回此套接字连接的地址
    5 int    getPort();//返回此套接字的端口

     (2)、DatagramPacket类常用方法

    此类表示数据报包

    1、构造方法

    1 new    DatagramPacket(byte[] buf,int length,InetAddress address,int port);//构造数据报包,用来将长度为length的包发送到指定主机上的指定端口号
    2 new  DatatgramPacket(byte[] buf,int length);//构造 DatagramPacket,用来接收长度为 length 的数据包

     2、一般方法

    1 InetAddress    getAddress();//获取某台主机的ip地址
    2 byte[]    getData();//获取数据缓冲区的内容
    3 int    getLength();//获取将要发送或者接收到的数据的长度
    4 int    getPort();//获取某台主机的端口号

     2、UDP传输发送和获取数据的步骤

    UDP发送端步骤:

      1)、建立UDPSocket服务

      2)、提供数据,并将数据封装到数据包中

      3)、通过Socket服务的send方法,将数据包发送出去

      4)、关闭资源 

    UDP接收端步骤:

      1)、定义UDPSocket服务。通常会监听一个端口号。其实就是给这个接收网络应用程序定义数字标识,方便于明确哪些数据过来哪个应该程序可以处理

      2)、定义一个数据包。因为要存储接收到的字节数据。因为数据包对象中有更多功能可以提取字节数据中的不同数据信息

      3)、通过Sockt服务的receive方法将接收到的数据存入已经定义好的数据包中

      4)、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上

      5)、关闭资源

     需求:聊天程序(双窗口模式)代码演示:

     1 import java.io.*;
     2 import java.net.*;
     3 class UDPSend 
     4 {
     5     public static void main(String[] args) 
     6     {
     7         DatagramSocket ds=null;        
     8         BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
     9         try        
    10         {
    11             //1,创建udp服务。通过DatagramSocket对象。
    12             ds=new DatagramSocket();
    13             String line=null;
    14             while ((line=br.readLine())!=null)
    15             {
    16                 byte[] buf=line.getBytes();
    17                 //2,确定数据,并封装成数据包。DatagramPacket(byte[] buf,int length, InetAddress address, int port) 
    20                 DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.104"),55128);
    23                 //3,通过socket服务,将已有的数据包发送出去。通过send方法 26                 ds.send(dp);
    27                 if("over".equals(line))
    28                     break;
    29             }
    30             
    31         }
    32         catch (Exception e)
    33         {
    34             System.out.println(e);
    35         }
    36         finally
    37         {
    38             if(ds!=null)
    39                 try
    40                 {
    41                     //4,关闭资源。
    42                     ds.close();
    43                 }
    44                 catch (Exception e)
    45                 {
    46                     System.out.println("发送端关闭失败");
    47                 }
    48         }
    49     }
    50 }
    51 class UDPReceive
    52 {
    53     public static void main(String[] args){
    54         DatagramSocket ds=null;
    55         DatagramPacket dp=null;
    56         try{
    57             //1,创建udp socket,建立端点。
    58             ds=new DatagramSocket(55128);        
    59             while (true)
    60             {    //2,定义数据包。用于存储数据。            
    61                 byte[] buf=new byte[1024];
    62                 dp=new DatagramPacket(buf,buf.length);
    63                 //3,通过服务的receive方法将收到数据存入数据包中。
    64                 ds.receive(dp);//阻塞式方法。
    65                 //4,通过数据包的方法获取其中的数据。
    66                 String ip=dp.getAddress().getHostAddress();
    67                 String data=new String(dp.getData(),0,dp.getLength());
    68                 System.out.println(ip+"......"+data);
    69                 if(data.equals("over"))
    70                     break;
    71             }
    72             
    73         }
    74         catch (Exception e)
    75         {
    76             System.out.println(e);
    77         }
    78         finally
    79         {
    80             if(ds!=null)
    81                 try
    82                 {
    83                     //5,关闭资源
    84                     ds.close();
    85                 }
    86                 catch (Exception e)
    87                 {
    88                     System.out.println("接收端关闭失败");
    89                 }
    90         }
    91     }
    92 }

     需求:聊天程序(单窗口模式-群聊)代码演示:

    收数据的部分,和发数据的这两部分需要同时执行。那就需要用到多线程技术。一个线程控制收,一个线程控制发。因为收和发动作是不一致的,所以要定义两个run方法。而且这两个方法要封装到不同的类中。

     1 import java.io.*;
     2 import java.net.*;
     3 class UDPSend implements Runnable
     4 {
     5     private DatagramSocket ds;
     6     UDPSend(DatagramSocket ds){
     7         this.ds=ds;
     8     }
     9     public void run(){
    10         try
    11         {
    12             //读取键盘录入
    13             BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    14             String line=null;
    15             while ((line=br.readLine())!=null)
    16             {
    17                 byte[] buf=line.getBytes();
    18                 //定义数据包,用来存放数据
    19                 DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.104"),5556);
    20                 //通过send方法把数据发送给接收端
    21                 ds.send(dp);
    22                 if("over".equals(line))
    23                     break;
    24             }
    25             ds.close();
    26         }
    27         catch (Exception e)
    28         {
    29             System.out.println("发送失败");
    30         }
    31     }
    32 }
    33 class UDPReceive implements Runnable
    34 {
    35     private DatagramSocket ds;
    36     UDPReceive(DatagramSocket ds){
    37         this.ds=ds;
    38     }
    39     public void run(){//复写run方法
    40         try
    41         {
    42             while (true)
    43             {
    44                 byte[] buf=new byte[1024];
    45                 //定义数据包用来接收发送端发过来的数据信息
    46                 DatagramPacket dp=new DatagramPacket(buf,buf.length);
    47                 //接收数据
    48                 ds.receive(dp);
    49                 //对接收过来的数据进行ip地址等信息的解析
    50                 String ip=dp.getAddress().getHostAddress();
    51                 String data=new String(dp.getData(),0,dp.getLength());
    52                 System.out.println(ip+"......."+data);
    53                 if("over".equals(data))
    54                     break;
    55             }
    56             ds.close();            
    57         }
    58         catch (Exception e)
    59         {
    60             System.out.println("接收端接受失败");
    61         }
    62     }
    63 }
    64 class ChatRoom
    65 {
    66     public static void main(String[] args)throws Exception{
    67         //定义两个DatagramSocket服务
    68         DatagramSocket send=new DatagramSocket();
    69         DatagramSocket receive=new DatagramSocket(5556);
    70         //开启两个线程
    71         new Thread(new UDPSend(send)).start();
    72         new Thread(new UDPReceive(receive)).start();
    73     }
    74 }

     三、TCP协议-客户端和服务端

    客户端(Client)首先与服务端(Server)建立连接,形成通道(其实就是IO流),然后,数据就可以在通道之间进行传输,并且单个Server端可以同时与多个Client端建立连接。Socket和ServerSocket,建立客户端和服务器端。建立连接后,通过Socket中的IO流进行数据的传输。关闭socket。同样,客户端与服务器端是两个独立的应用程序。

    TCP客户端

    客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream()和getOutputStream()获取即可与服务端通讯。结束后关闭Socket。客户端,通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。因为tcp是面向连接的。所以在建立socket服务时,就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。

    TCP服务端

    服务端需要明确它要处理的数据是从哪个端口进入的。当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。当该客户端访问结束,关闭该客户端。1,建立服务端的socket服务。ServerSocket();并监听一个端口。2,获取连接过来的客户端对象。通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。并打印在控制台。4,关闭服务端。(可选)。

    TCP协议因为是面向连接的。所以传输数据必须先开服务端,再开客户端。否则,客户端根本连接不上服务端。

    1、Socket类中常用方法

    (1)、构造方法

    1 new    Socket();
    2 new    Socket(InetAddress address,int port);//创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
    3 new    Socket(String host,int port);// 创建一个流套接字并将其连接到指定主机上的指定端口号。

     (2)、成员方法

    1 void  bind(SocketAddress bindpoint);//将套接字绑定到本地地址。 
    2 void  connect(SocketAddress endpoint);//将此套接字连接到服务器。 
    3 InetAddress  getInetAddress();//返回套接字连接的地址。
    4 InputStream  getInputStream();//返回此套接字的输入流。
    5 OutputStream  getOutputStream();// 返回此套接字的输出流。 
    6 int  getPort();// 返回此套接字连接到的远程端口 
    7 void  shutdownInput();// 此套接字的输入流置于“流的末尾”。 
    8 void  shutdownOutput();// 禁用此套接字的输出流 

     2、ServerSocket类中常用方法

    (1)、构造方法

    1 new    ServerSocket();//创建非绑定服务器套接字。
    2 new    ServerSocket(int port);//创建绑定到特定端口的服务器套接字。

     (2)、成员方法

    1  Socket  accept();//侦听并接受到此套接字的连接。 
    2 InetAddress  getInetAddress();// 返回此服务器套接字的本地地址。 

     需求:TCP协议-服务端和客户端交互代码演示:

     1 import java.io.*;
     2 import java.net.*;
     3 class  TCPClient
     4 {
     5     public static void main(String[] args) throws Exception
     6     {
     7         //创建客户端的socket服务。指定目的主机和端口
     8         Socket s=new Socket("192.168.1.100",5544);
     9         //为了发送数据,应该获取socket流中的输出流。
    10         OutputStream out=s.getOutputStream();
    11         out.write("TCP,我来了!".getBytes());
    12         InputStream in=s.getInputStream();
    13         byte[] buf=new byte[1024];
    14         int len=in.read(buf);
    15         System.out.println(new String(buf,0,len));
    16         s.close();
    17     }
    18 }
    19 class TCPServer
    20 {
    21     public static void main(String[] args)throws Exception{
    22         //建立服务端socket服务。并监听一个端口。
    23         ServerSocket ss=new ServerSocket(5544);
    24         //通过accept方法获取连接过来的客户端对象。
    25         Socket s=ss.accept();
    26         //获取ip地址
    27         String ip=s.getInetAddress().getHostAddress();
    28         System.out.println(ip+".....connnect");
    29         //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
    30         InputStream in=s.getInputStream();
    31         byte[] buf=new byte[1024];
    32         int len=in.read(buf);
    33         System.out.println(new String(buf,0,len));
    34 
    35         OutputStream out=s.getOutputStream();
    36         out.write("收到".getBytes());
    37         ss.close();
    38         //关闭客户端.
    39         s.close();
    40     }
    41 }

     需求:建立一个文本转换服务器。

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

    客户端:

    既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。

    源:键盘录入。

    目的:网络设备,网络输出流。

    而且操作的是文本数据。可以选择字符流。

    步骤

    1,建立服务。

    2,获取键盘录入。

    3,将数据发给服务端。

    4,后去服务端返回的大写数据。

    5,结束,关资源。

    都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。

    服务端:

    源:socket读取流。

    目的:socket输出流。

    都是文本,装饰。

     1 import java.io.*;
     2 import java.net.*;
     3 class TransClient 
     4 {
     5     public static void main(String[] args) throws Exception
     6     {
     7         Socket s=new Socket("192.168.1.100",7788);
     8         //定义读取键盘数据的流对象。
     9         BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    10         //定义目的,将数据写入到socket输出流。发给服务端。
    11         PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    12         //定义一个socket读取流,读取服务端返回的大写信息。
    13         BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
    14         String line=null;
    15         while ((line=br.readLine())!=null)
    16         {
    17             out.println(line);
    18             if("over".equals(line))
    19                 break;
    20             String info=in.readLine();        
    21             System.out.println("info="+info);
    22         }
    23         s.close();
    24 
    25     }
    26 }
    27 class TransServer
    28 {
    29     public static void main(String[] args)throws Exception{
    30         ServerSocket ss=new ServerSocket(7788);        
    31         Socket s=ss.accept();
    32         System.out.println(s.getInetAddress().getHostAddress()+".....connect");
    33         //读取socket读取流中的数据。
    34         BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
    35         //目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。
    36         PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    37         String line=null;
    38         while ((line=in.readLine())!=null)
    39         {
    40             System.out.println(line);
    41             out.println(line.toUpperCase());
    42             if("over".equals(line))
    43                 break;
    44         }
    45         s.close();
    46         ss.close();
    47     }
    48 }

     需求:TCP协议上传文本文件

     1 import java.io.*;
     2 import java.net.*;
     3 class  TCPClient
     4 {
     5     public static void main(String[] args)throws Exception
     6     {
     7         Socket s=new Socket("192.168.1.100",9999);
     8         BufferedReader br=new BufferedReader(new FileReader("TCPDemo.java"));
     9         PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    10         BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
    11         String line=null;
    12         while ((line=br.readLine())!=null)
    13         {
    14             out.println(line);
    15         }
    16         s.shutdownOutput();//关闭客户端的输出流。相当于给流中加入一个结束标记-1.
    17         System.out.println(in.readLine());
    18         s.close();
    19         br.close();
    20     }
    21 }
    22 class TCPServer
    23 {
    24     public static void main(String[] args)throws Exception{
    25         ServerSocket ss=new ServerSocket(9999);
    26         Socket s=ss.accept();
    27         System.out.println(s.getInetAddress().getHostAddress()+"....connect");
    28         BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
    29         PrintWriter pw=new PrintWriter(new FileWriter("E:\TCPDemo.java"),true);
    30         PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    31         String line=null;
    32         while ((line=in.readLine())!=null)
    33         {
    34             pw.println(line);
    35         }
    36         out.println("上传成功");
    37         s.close();
    38         ss.close();
    39         pw.close();
    40     }
    41 }

     需求:TCP客户端并发上传图片代码演示:

    服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。

    如何定义线程呢?

    只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。

     1 import java.io.*;
     2 import java.net.*;
     3 class PicClient
     4 {
     5     public static void main(String[] args)throws Exception{
     6         File file=new File(args[0]);
     7         if(!(file.exists()&& file.isFile())){
     8             System.out.println("请上传图片");
     9             return;
    10         }
    11         if(!(file.getName().endsWith(".jpg"))){
    12             System.out.println("上传格式错误");
    13             return;
    14         }
    15         if(file.length()>=1024*1024*4){
    16             System.out.println("文件过大,请切割后上传");
    17             return;
    18         }
    19 
    20         Socket s=new Socket("192.168.1.104",5555);
    21         FileInputStream fis=new FileInputStream(file);
    22         OutputStream out=s.getOutputStream();
    23         byte[] buf=new byte[1024];
    24         int len=0;
    25         while ((len=fis.read(buf))!=-1)
    26         {
    27             out.write(buf,0,len);
    28         }
    29         s.shutdownOutput();//告诉服务端数据已写完
    30         InputStream in=s.getInputStream();
    31         byte[] bufIn=new byte[1024];
    32         int num=in.read(bufIn);
    33         System.out.println(new String(bufIn,0,num));
    34         s.close();
    35         fis.close();
    36     }
    37 }
    38 class PicThread implements Runnable
    39 {
    40     private Socket s;
    41     PicThread(Socket s){
    42         this.s=s;
    43     }
    44     public void run(){
    45         String ip=s.getInetAddress().getHostAddress();
    46         System.out.println(ip+".....connect");
    47         try
    48         {
    49             int count=1;
    50             //创建file对象
    51             File file=new File("E:\"+ip+"("+count+")"+".jpg");
    52             //如果file文件存在则count++,直到不存在为止
    53             while(file.exists())
    54                 file=new File("E:\"+ip+"("+(count++)+")"+".jpg");
    55             InputStream in=s.getInputStream();
    56             FileOutputStream fos=new FileOutputStream(file);
    57             byte[] buf=new byte[1024];
    58             int len=0;
    59             while ((len=in.read(buf))!=-1)
    60             {
    61                 fos.write(buf,0,len);
    62             }
    63             OutputStream out=s.getOutputStream();
    64             out.write("上传成功".getBytes());
    65             s.close();            
    66         }
    67         catch (Exception e)
    68         {
    69             System.out.println(ip+"连接成功");
    70         }
    71     }
    72 }
    73 class PicServer
    74 {
    75     public static void main(String[] args)throws Exception{
    76         ServerSocket ss=new ServerSocket(5555);
    77         while (true)
    78         {
    79             Socket s=ss.accept();
    80             new Thread(new PicThread(s)).start();
    81         }
    82     }
    83 }

     需求:客户端通过键盘录入用户名。服务端对这个用户名进行校验。最多就登录三次。

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

    并在客户端显示 xxx,欢迎光临。

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

    并在客户端显示 xxx,该用户不存在。

     1 import java.io.*;
     2 import java.net.*;
     3 class LoginClient 
     4 {
     5     public static void main(String[] args)throws Exception
     6     {
     7         Socket s=new Socket("192.168.1.104",6666);
     8         BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
     9         //读取socket流中的读取流
    10         BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
    11         //socket流中的输出流
    12         PrintWriter out=new PrintWriter(s.getOutputStream(),true);    
    13         //循环3次输入,如果输入为null,直接停止输入
    14         for (int x=0;x<3 ;x++ )
    15         {
    16             String name=br.readLine();
    17             if(name==null)
    18                 break;
    19             out.println(name);
    20             String info=in.readLine();
    21             System.out.println(info);
    22             //如果获取到流中有“欢迎“字样,说明对方已经登录,这时候即使输入的不到3次,也停止输入,因为已经登录成功了。
    23             if(info.contains("欢迎")){                
    24                 break;
    25             }
    26         }
    27         s.close();
    28     }
    29 }
    30 class LoginThread implements Runnable
    31 {
    32     private Socket s;
    33     LoginThread(Socket s){
    34         this.s=s;
    35     }
    36     public void run(){
    37         String ip=s.getInetAddress().getHostAddress();
    38         System.out.println(ip+".....connect");
    39         try
    40         {                
    41             for (int x=0;x<3 ;x++ )
    42             {
    43                 //读取socket流中的输入流
    44                 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
    45                 String name=in.readLine();
    46                 if(name==null)
    47                     break;
    48                 //读取文件
    49                 BufferedReader br=new BufferedReader(new FileReader("Userinfo.txt"));
    50                 //socket流输出流
    51                 PrintWriter out=new PrintWriter(s.getOutputStream(),true);    
    52                 //定义一个标记, 从socket输入流中的键盘数据判断user.txt中是否有name符合,如果有标记为真,跳出while循环。
    53                 boolean flag=false;
    54                 String line=null;
    55                 while ((line=br.readLine())!=null)
    56                 {
    57                     //判断Userinfo.txt和name是否有相同的
    58                     if(line.equals(name)){
    59                         flag=true;
    60                         break;
    61                     }
    62                 }
    63                 if(flag){
    64                     System.out.println(name+",已登陆");
    65                     out.println(name+",欢迎光临");
    66                     break;
    67                 }
    68                 else{
    69                     System.out.println(name+",尝试登陆");
    70                     out.println(name+",该用户不存在");
    71                 }
    72             }
    73             s.close();
    74         }
    75         catch (Exception e)
    76         {
    77             System.out.println(ip+"连接失败");
    78         }
    79     }
    80 }
    81 class LoginServer
    82 {
    83     public static void main(String[] args)throws Exception{
    84         ServerSocket ss=new ServerSocket(6666);
    85         while (true)
    86         {
    87             Socket s=ss.accept();
    88             new Thread(new LoginThread(s)).start();
    89         }
    90     }
    91 }

     四、客户端和服务器端原理

    最常见的客户端:浏览器,IE/chrome。

    最常见的服务端:服务器,Tomcat。

    1. 自定义服务端

    使用已有的客户端IE,了解一下客户端向服务端发了什么请求

     1 import java.io.*;
     2 import java.net.*;
     3 class ServerDemo 
     4 {
     5     public static void main(String[] args) throws Exception
     6     {
     7         ServerSocket  ss=new ServerSocket(8080);
     8         Socket s=ss.accept();
     9         PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    10         out.println("<font size='5' color='red'>客户端你好 </font>");
    11         //获取到服务器向客户端发送的数据
    12         InputStream is=s.getInputStream();        
    13         byte[] buf=new byte[1024];        
    14         int len=is.read(buf);
    15         System.out.println(new String(buf,0,len));
    16         ss.close();
    17         s.close();        
    18     }
    19 }
    20 /*这是服务器向客户端发送的数据
    21 (请求行,请求方式:GET;请求的资源路径:/;HTTP协议版本:1.1。)
    22 GET / HTTP/1.1
    23 (请求消息头,属性名:属性值)
    24 Host: 127.0.0.1:8080
    25 Connection: keep-alive
    26 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0
    27 .8
    28 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like
    29 Gecko) Chrome/42.0.2311.152 Safari/537.36
    30 Accept-Encoding: gzip, deflate, sdch
    31 Accept-Language: zh-CN,zh;q=0.8
    32 */

     HTTP是一个客户端和服务端请求和应答的标准,客户端按照HTTP的标准发送数据到服务端,服务端按照HTTP的标准解析收到的数据。很多软件都内置了此标准。

    2. 模拟一个浏览器获取信息。

     1 import java.net.*;
     2 import java.io.*;
     3 public class MyBrowser
     4 {
     5         public static void main(String[] args) throws IOException {                
     6                 Socket s = new Socket("192.168.1.100",8080);
     7                 //模拟浏览器,向tomcat服务端发送符合http协议的请求消息。
     8                 PrintWriter out = new PrintWriter(s.getOutputStream(),true);
     9                 out.println("GET /myweb/1.html HTTP/1.1");
    10                 out.println("Accept: */*");
    11                 out.println("Host: 192.168.1.100:8080");
    12                 out.println("Connection: close");
    13                 out.println();
    14                 out.println();
    15                 InputStream in = s.getInputStream();
    16                 byte[] buf = new byte[1024];
    17                 int len = in.read(buf);
    18                 String str = new String(buf,0,len);
    19                 System.out.println(str);
    20                 s.close();
    21         }
    22 }

     HTTP服务端发回的应答消息:

    (应答行,HTTP的协议版本:1.1;应答状态码:200;应答状态描述信息:OK。)

            HTTP/1.1 200 OK

            (应答消息属性信息,属性名:属性值。)

            Server: Apache-Coyote/1.1

            Accept-Ranges: bytes

            ETag: W/"211-1433908112666"

            Last-Modified: Wed, 10 Jun 2015 03:48:32 GMT

            Content-Type: text/html

            Content-Length: 211

            Date: Wed, 10 Jun 2015 03:52:16 GMT

            Connection: close

    应答行中属性名及属性值的具体含义,初学者不用追究,在JavaWeb课程中将会深入讲解。

    五、URL和URLConnection类

    URI:统一资源标示符。

    URL:统一资源定位符,也就是说根据URL能够定位到网络上的某个资源,它是指向互联网“资源”的指针。每个URL都是URI,但不一定每个URI都是URL。这是因为URI还包括一个子类,即统一资源名称(URN),它命名资源但不指定如何定位资源。

    URL类可以建立到远程对象的连接,也就是说这里面封装了socket,可以直接获取socket流。

    1、常用方法

    1 String   getFile();//获取此 URL 的文件名。 
    2 String   getHost();//获取此 URL 的主机名(如果适用)。 
    3 String   getPath();//获取此 URL 的路径部分。 
    4 int      getPort();//获取此 URL 的端口号。 
    5 String   getProtocol();//获取此 URL 的协议名称。 
    6 String   getQuery();//获取此 URL 的查询部分。
    7 URLConnection   openConnection();//返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。
    8 InputStream   openStream();//打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。此方法是下面方法的缩写: 
    9 openConnection().getInputStream()。

     代码演示:

     1 import java.net.*;
     2 import java.io.*;
     3 class  URLConnectionDemo
     4 {
     5     public static void main(String[] args) throws Exception
     6     {
     7         URL url = new URL("http://192.168.1.254:8080/myweb/demo.html");
     8 
     9         URLConnection conn = url.openConnection();
    10         System.out.println(conn);
    11         
    12         InputStream in = conn.getInputStream();
    13 
    14         byte[] buf = new byte[1024];
    15 
    16         int len = in.read(buf);
    17 
    18         System.out.println(new String(buf,0,len));

      之所以运行结果中响应头不见了,只能看到主体数据的原因在于:URLConnection对象已经把响应头给解析了。

    六、域名解析

    在浏览器中输入新浪的域名,DNS解析域名成IP,然后计算机再通过获取到的IP访问新浪服务器。

    域名解析,最先走是本地的hosts(C:WINDOWSsystem32driversetchosts)文件,解析失败了,才去访问DNS服务器解析、获取IP地址。

    可以通过hosts文件可以屏蔽游戏网站内容弹出。

  • 相关阅读:
    MySQL数据库开发的36条原则
    su和sudo的区别与使用
    利用modelarts和物体检测方式识别验证码
    华为云大咖说-庄表伟:架构师的基本功——管理篇
    【玩转MLS系列】基础教程
    Java程序性能优化
    洛谷P4551 最长异或路径
    POJ 2001 Shortest Prefixes
    线段树区间修改
    接毒瘤
  • 原文地址:https://www.cnblogs.com/521Android/p/4732976.html
Copyright © 2011-2022 走看看