java-网络编程

1 网络模型

 

 

 

 

2 网络通讯要素

IP

网络中的标识

本地回环地址:127.0.01 主机名 localhost

端口

用于标识进程的逻辑地址,不同的进程的标识

有效的端口0-65535  0-1024 系统使用或保留端口

 

 

 

 

 

 传输协议

通讯的规则

常见协议:TCP UDP

UDP:对讲机

TCP:打电话

 

 

3 域名解析

 

 4 UDP

1,发送时,创建待了送数据包pack,其中指定目标主机的ip地址和接收的端口

调用DatagemSocket send(pack)方法发送pack数据报,发送端口由java绑定一个可用的端口

2,接收时,创建指定的端口的DatagramScoket 调用基receve(pack)方法招收数据报接收的数据存放在pack包的缓冲区中,在调用pack.getData()方法获得里面的数据

接收方必须指定接收端口,该接收端口正是发送数据包中指定的端口,而发送端口可以是任意一个可用的端口

发送

/*
         * 思路:
         * 1,建立udp的socket服务,
         * 2,将要发送的数据封装支数据包中去
         * 3,通过udp的socket服务将数据包发送出去
         * 4,关闭socket服务
         * 
         * */
        
        System.out.println("发送端启动");
        DatagramSocket ds = new DatagramSocket();
        
        
        String str= "我来了";
        byte [] buf = str.getBytes();
        
        DatagramPacket dp = 
                new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 10000);
        
        ds.send(dp);
        ds.close();

接收

/*
         * 接收端
         * 思路:
         * 1,建立scoket服务,因为要接收数据,必须要明确端口号
         * 2,创建数据包,用于存储接收到的数据,方便解析
         * 3.使用scoket服务的receive方法接收的数据存储到数据包中
         * 4,通过数据包的方法解析数据包的数据
         * 5.关闭资源
         * 
         * */
        
        
        System.out.println("接收启动");
        // 建立 udp scoket服务
        DatagramSocket ds = new DatagramSocket(10000);
        
        // 创建数据包
        byte [] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf,buf.length);
        
        // 使用接收方法
        ds.receive(dp);
        // 通过数据包的方法.解析数据.比如:地址,端口,数据内容
        String ip = dp.getAddress().getHostAddress();
        
        int port = dp.getPort();
         
        String text = new String (dp.getData(),0,dp.getLength());
        System.out.println(ip+":"+port+":" + text);
        
        ds.close();

5 聊天程序

发送端

DatagramSocket ds = new DatagramSocket();

                  // 加上键盘录入

                  BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

                  String line = null;

                  while((line = bufr.readLine())!= null){

                          byte [] buf = line.getBytes();

                          DatagramPacket dp =

                                            new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 10001);

                          ds.send(dp);

                          if("over".equals(line))

                                   break;

                  }

接收端

Whlie循环,让它一直接收

上面是两个进程的工作,还要切换进程 ,可以创建两个线程,让它在五一个

进程中.这时要用到线程技术

发送端

class Test implements Runnable {

         private DatagramSocket ds;

         public Test (DatagramSocket ds){

                  this.ds=ds;

         }

        

 

        

 

         @Override

         public void run() {

                  try{

                          System.out.println("发送端启动");

                 

                  // 加上键盘录入

                  BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

                  String line = null;

                  while((line = bufr.readLine())!= null){

                          byte [] buf = line.getBytes();

                          DatagramPacket dp =

                                            new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 10002);

                          ds.send(dp);

                          if("over".equals(line))

                                   break;

                  }

                  ds.close();

                  }catch(Exception e){

                         

                  }

                 

         }

}

 

接收端

public class Test2 implements Runnable {

         private DatagramSocket ds ;

         public Test2(DatagramSocket ds){

                  this.ds=ds;

                  }

 

         @Override

         public void run() {

                  try{

                         

                         

                          while(true){

                          System.out.println("接收启动");

                          // 建立 udp scoket服务

                         

                          // 创建数据包

                          byte [] buf = new byte[1024];

                          DatagramPacket dp = new DatagramPacket(buf,buf.length);

                         

                          // 使用接收方法

                          ds.receive(dp);

                          // 通过数据包的方法.解析数据.比如:地址,端口,数据内容

                          String ip = dp.getAddress().getHostAddress();

                         

                          int port = dp.getPort();

                           

                          String text = new String (dp.getData(),0,dp.getLength());

                          System.out.println(ip+":"+port+":" + text);

                          }

                         

                  }catch(Exception e){

                         

                  }

                 

         }

        

}

数据测试

         public static void main(String[] args) throws SocketException {

 

                  DatagramSocket send = new DatagramSocket();

                  DatagramSocket rec = new DatagramSocket(10002);

                  Test s = new Test (send);

                  Test2 r = new Test2(rec);

                  new Thread(s).start();

                  new Thread(r).start();      

6 TCP

客户端

// tcp传输.客户端建立过程

                  /*

                   *

                   * 1,创建tcp 客户端socket服务,使用的是scoket对象

                   * 2.如果连接建立成功,说明数据通道连接成功

                   *    可以通过getOutputSteam() 和getInputStream来获取两个字节流

                   * 3, 使用输出流 或者输入流

                   *

                   * */

                 

                  // 创建客户端服务

                  Socket socket = new Socket("127.0.0.1",20000);

                  //获取流

                  OutputStream out = socket.getOutputStream();

                 

                  // 使用输出流将指定的数据写出去

                  out.write("人的家".getBytes());

                  // 关闭资源

                  socket.close();                 

服务端

public static void main(String[] args) throws IOException {

                  /*

                   * 建立tcp服务端折思路

                   * 1,创建服务端socket服务,通过serverSocket对象

                   * 2,服务端必须提供一个端口,否则客户端无法连接

                   * 3, 获取连接过来的客户端对象

                   * 4,通过客户端对象获取 socket流读取客户端发来的数据

                   * 5.关闭资源,关客房端,关服务端

                   *

                   * */

                 

                  ServerSocket ss = new ServerSocket(20000);

                 

                  Socket s = ss.accept();

                  String ip = s.getInetAddress().getHostAddress();

                  InputStream in = s.getInputStream();

                  byte [] buf = new  byte [1024];

                  int len = in.read(buf);

                  String text =new String (buf,0,len);

                  System.out.println("server:"+text);

                 

                  System.out.println(ip);

                  s.close();

                  ss.close();

                 

                 

         }

 

7 文本转换

易错点:

1,结束标记的原理

2,当遇到上传过程中,会发生都在阻塞状态,

文本转换-客户端

public class TransClient {

 

         /**

          * @param args

          * @throws IOException

          * @throws 

          */

         public static void main(String[] args) throws IOException {

                  System.out.println("客户端运行......");

                  // 客户端:

                  // 步骤:

                  // 1,创建socket,明确地址和端口。

                  Socket s = new Socket("192.168.1.223", 10005);

 

                  // 2,源:键盘录入。获取需要转换的数据。

                  BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

                 

                  // 3,目的:网络,socket输出流。将录入的数据发送到服务端。

//              OutputStream out = s.getOutputStream();

                  //既然都是字符数据,为了便于操作,使用额外功能,转换。同时提高效率。

                  //BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(out));可以使用打印流

                  PrintWriter out = new PrintWriter(s.getOutputStream(),true);

                 

                  // 4,源:socket,socket读取流,读取服务端发回来的大写数据。

//              InputStream in = s.getInputStream();

                  BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

                 

                  // 5,目的:客户端显示器,将大写数据显示出来。直接使用输出语句。

                 

                  // 6,频繁的读写操作。

                  String line = null;

                  while((line=bufr.readLine())!=null){

                         

                          //将读取键盘的数据发送到服务端。

                          out.println(line);

//                       out.flush();

                          if("over".equals(line)){

                                   break;

                          }

                         

                          //读取服务端返回的数据。

                          String upperText = bufIn.readLine();

                          System.out.println(upperText);

                  }

                 

                  // 7,关闭资源。

                  s.close();

         }

 

}

文本转换-服务端

public class TransServer {

 

         /**

          * @param args

          * @throws IOException

          */

         public static void main(String[] args) throws IOException {

 

                  System.out.println("服务端运行....");

                  // 服务端:

                  // 思路:

                  // 1,创建服务端socket 明确端口。

                  ServerSocket ss = new ServerSocket(10005);

                  while (true) {

                          // 获取客户端对象。

                          Socket s = ss.accept();

                          System.out.println(s.getInetAddress().getHostAddress()+".....connected");

 

                          // 2,源:socket输入流。读取客户端的发过来的数据。

                          BufferedReader bufIn = new BufferedReader(new InputStreamReader(

                                            s.getInputStream()));

 

                          // 3,目的:socket输出流。将转成大写的数据发送给客户端。

                          PrintWriter out = new PrintWriter(s.getOutputStream(),true);

 

                          // 4,频繁的读写操作。

                          String line = null;

                          while ((line = bufIn.readLine()) != null) {

                                   if("over".equals(line)){//如果客户端发过来的是over,转换结束。

                                            break;

                                   }

                                   System.out.println(line);

                                   // 将读取到的字母数据转成大写,发回给客户端。

                                   out.println(line.toUpperCase());

//                                out.flush();

                          }

                          // 5,关闭客户端。

                          s.close();

                  }

 

         }

 

}

8 上传文件

易错点:

1结束标记的原理

客户端

public static void main(String[] args) throws UnknownHostException, IOException {

                  System.out.println("上传文件客户端运行......");

                  // 客户端:

                  // 步骤:

                  // 1,创建socket,明确地址和端口。

                  Socket s = new Socket("192.168.1.223", 10006);

 

                  // 2,源:读取文本文件。获取需要转换的数据。

                  BufferedReader bufr = new BufferedReader(new FileReader("tempfile\\client.txt"));

                 

                  // 3,目的:网络,socket输出流。将录入的数据发送到服务端。

                  PrintWriter out = new PrintWriter(s.getOutputStream(),true);

                 

                  // 4,频繁的读写操作。

                  String line = null;

                  while((line=bufr.readLine())!=null){

                         

                          out.println(line);

                         

                  }

                 

                  //给服务端发送一个结束标记。这个标记是约定标记。有点麻烦。可以更简单。使用socket对象的shutdownOutput();

//              out.println("over");

                  s.shutdownOutput();//向服务端发送了结束标记。可以让服务端结束读取的动作。

                 

                 

                  // 5,源:socket,socket读取流,读取服务端发回来的上传成功信息。

                  BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

                  String info = bufIn.readLine();

                  System.out.println(info);

                 

                  // 6,关闭资源。

                  bufr.close();

                  s.close();

 

 

         }

服务器端

public static void main(String[] args) throws IOException {

 

 

                  System.out.println("上传文本服务端运行....");

                  // 服务端:

                  // 思路:

                  // 1,创建服务端socket 明确端口。

                  ServerSocket ss = new ServerSocket(10006);

                  while (true) {

                          // 获取客户端对象。

                          Socket s = ss.accept();

                          System.out.println(s.getInetAddress().getHostAddress()+".....connected");

 

                          // 2,源:socket输入流。读取客户端的发过来的数据。

                          BufferedReader bufIn = new BufferedReader(new InputStreamReader(

                                            s.getInputStream()));

 

                          // 3,目的:文件。

                          PrintWriter pw = new PrintWriter(new FileWriter("tempfile\\server.txt"),true);

 

                          // 4,频繁的读写操作。

                          String line = null;

                          while ((line = bufIn.readLine()) != null) {

//                                if("over".equals(line)){

//                                        break;

//                                }

                                   pw.println(line);

                          }

                         

                          // 5,发回给客户端上传成功字样。

                          PrintWriter out = new PrintWriter(s.getOutputStream(),true);

                          out.println("上传成功");

                         

                          // 6,关闭客户端。

                          s.close();

                  }

 

 

         }

 

9 字符流不可以传输媒体文件

有可能你在查表时不能查到,造成你你原来文件和转换后的不一样.

比如下面图片里面的”1122”,查不到,那么表会给他一个默认的编码”1122”

 

 

10 上传图片

客户端

上面图片要用到字节流

public static void main(String[] args) throws IOException {

                  System.out.println("上传图片客户端运行......");

                  //1,创建socket。

                  Socket s = new Socket("192.168.1.223", 10007);

                 

                  //2,读取源图片。

                  File picFile = new File("tempfile\\1.jpg");

                  FileInputStream fis = new FileInputStream(picFile);

                 

                  //3,目的是socket 输出流。

                  OutputStream out = s.getOutputStream();

                 

                  byte[] buf = new byte[1024];

                 

                  int len = 0;

                  while((len=fis.read(buf))!=-1){

                          out.write(buf,0,len);

                  }

                 

                  //告诉服务器端图片数据发送完毕,不要等着读了。

                  s.shutdownOutput();

                 

                  //读取上传成功字样。

                  InputStream in = s.getInputStream();

                  byte[] bufIn = new byte[1024];

                  int lenIn = in.read(bufIn);

                  System.out.println(new String(bufIn,0,lenIn));

                 

                 

                  //关闭。

                  fis.close();

                  s.close();

 

         }

服务端

String ip = s.getInetAddress().getHostAddress();

                          System.out.println(ip + ".....connected");

 

                          // 读取图片数据。

                          InputStream in = s.getInputStream();

 

                          // 写图片数据到文件。

                          File dir = new File("e:\\uploadpic");

                          if (!dir.exists()) {

                                   dir.mkdir();

                          }

                          // 为了避免覆盖,通过给重名的文件进行编号。

                          int count = 1;

                          File picFile = new File(dir, ip + "(" + count + ").jpg");

                          while (picFile.exists()) {

                                   count++;

                                   picFile = new File(dir, ip + "(" + count + ").jpg");

                          }

                          FileOutputStream fos = new FileOutputStream(picFile);

 

                          byte[] buf = new byte[1024];

                          int len = 0;

                          while ((len = in.read(buf)) != -1) {

                                   fos.write(buf, 0, len);

                          }

 

                          // 给客户端一个回馈信息。

                          OutputStream out = s.getOutputStream();

                          out.write("上传成功".getBytes());

 

                          // 关闭资源。

                          fos.close();

                          s.close();

解决重名覆盖问题

// 为了避免覆盖,通过给重名的文件进行编号。

                          int count = 1;

                          File picFile = new File(dir, ip + "(" + count + ").jpg");

                          while (picFile.exists()) {

                                   count++;

                                   picFile = new File(dir, ip + "(" + count + ").jpg");

                          }

解决并发问题

public void run() {

 

                  try {

                          String ip = s.getInetAddress().getHostAddress();

                           System.out.println(ip + ".....connected");

 

                          // 读取图片数据。

                          InputStream in = s.getInputStream();

 

                          // 写图片数据到文件。

                          File dir = new File("e:\\uploadpic");

                          if (!dir.exists()) {

                                   dir.mkdir();

                          }

                          // 为了避免覆盖,通过给重名的文件进行编号。

                          int count = 1;

                          File picFile = new File(dir, ip + "(" + count + ").jpg");

                          while (picFile.exists()) {

                                   count++;

                                   picFile = new File(dir, ip + "(" + count + ").jpg");

                          }

                          FileOutputStream fos = new FileOutputStream(picFile);

 

                          byte[] buf = new byte[1024];

                          int len = 0;

                          while ((len = in.read(buf)) != -1) {

                                   fos.write(buf, 0, len);

                          }

 

                          // 给客户端一个回馈信息。

                          OutputStream out = s.getOutputStream();

                          out.write("上传成功".getBytes());

 

                          // 关闭资源。

                          fos.close();

                          s.close();

                  } catch (IOException e) {

 

                  }

 

         }

 

 

11 Http

演示二:

         客户端:浏览器。

         服务端:自定义的服务端 myServer

         看到了如下信息:

HTTP的请求消息:请求头+请求体,中间有空行。

        

GET /myweb/1.html HTTP/1.1 // 请求行:请求方式   访问资源的路径  HTTP协议版本。

Accept: application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*

Accept-Language: zh-cn

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)

Host: 192.168.1.223:9090

Connection: Keep-Alive

空行

请求体 

演示三:模拟一个浏览器。

         客户端:自定义的浏览器。

         服务端:Tomcat

        

         发送和IE相同的HTTP协议的消息,收到了Tomcat服务器返回的数据。

        

HTTP的应答消息:

HTTP/1.1 200 OK  //应答行  http协议版本  应答状态码  应答描述信息

Server: Apache-Coyote/1.1

Accept-Ranges: bytes

ETag: W/"467-1374891778953"

Last-Modified: Sat, 27 Jul 2013 02:22:58 GMT

Content-Type: text/html

Content-Length: 467

Date: Sun, 01 Sep 2013 07:26:09 GMT

Connection: close

空行

应答体

 

我自己定义的服务器

public static void main(String[] args) throws IOException {

                 

                 

                  /*

                   *  自定义server 服务端

                   *  获取浏览器的信息。并反馈信息。

                   */

                  System.out.println("my server run....");

                  ServerSocket ss = new ServerSocket(9090);

                 

                  Socket s = ss.accept();

                  System.out.println(s.getInetAddress().getHostAddress()+"....connected");

                 

                  //读取客户端的数据。

                  InputStream in = s.getInputStream();

                  byte[] buf = new byte[1024];

                  int len = in.read(buf);

                  String text = new String(buf,0,len);

                  System.out.println(text);

                 

                  //给客户端回馈数据。

                  PrintWriter out = new PrintWriter(s.getOutputStream(),true);

                  out.println("<font color='red' size='7'>欢迎光临</font>");

                 

                 

                  s.close();

                  ss.close();

                 

 

         }

 

 

 

模拟客户端

/*

                   * 模拟一个浏览器。发送之前IE发送的http消息。

                   */

                  Socket s = new Socket("192.168.1.223",8080);

                  //把IE的信息发送给服务端。

                  PrintWriter out = new PrintWriter(s.getOutputStream(),true);

                  out.println("GET /myweb/3.html HTTP/1.1");

                  out.println("Accept: */*");

                  out.println("Host: 192.168.1.223:8080");

                  out.println("Connection: close");

                  out.println();//空行。

                 

                  //读取服务端的数据。

                  InputStream in = s.getInputStream();

                  byte[] buf = new byte[1024];

                  int len = in.read(buf);

                  String text = new String(buf,0,len);

                  System.out.println(text);

                 

                  s.close();

 

12 URL对象

Url常用方法和URLConnection

  

        */

         public static void main(String[] args) throws IOException {

                 

                  String str_url = "http://192.168.1.223:8080/myweb/2.html";

                 

                  //将url地址封装成对象。

                  URL url = new URL(str_url);

                 

//              System.out.println("getProtocol:"+url.getProtocol());

//              System.out.println("getHost:"+url.getHost());

//              System.out.println("getPort:"+url.getPort());

//              System.out.println("getPath:"+url.getPath());

//              System.out.println("getFile:"+url.getFile());

//              System.out.println("getQuery:"+url.getQuery());

                 

                  //获取指定资源的连接对象。//封装了socket。

                  URLConnection conn = url.openConnection();

                 

//              System.out.println(conn);

                 

                  InputStream in = conn.getInputStream();

                  byte[] buf = new byte[1024];

                  int len = in.read(buf);

                  String text = new String(buf,0,len);

                  System.out.println(text);

                 

         }

 

 

13 HTTP1.0和HTTP1.1区别

HTTP1.0:一次连接一次请求。

HTTP1.1:一次连接多次请求。

 

 

 

14 常见的网络架构

         C/S: client / server 

                  特点:

                          1,程序员需要开发客户端和服务端。

                          2,维护较为麻烦。

                          3,将一部分运算转移到客户端来完成,减轻服务器端的压力。

                 

        

         B/S: browser / server

                  特点:

                          1,程序员只需要开发服务端。客户端使用系统已有的浏览器即可。

                          2,维护很简单。只需要维护服务端。

                          3,所有的运算的都在服务端。

                         

         目前流行BS

 

 

 

posted @ 2018-01-28 23:09  8亩田  阅读(265)  评论(0编辑  收藏  举报