多线程,GUI,Socket网络编程

 

 

1.   多线程

 多线程概念

        线程与进程

    进程就是一个运行中的程序。

    一个进程中可以有多个线程,线程是CPU调度和分派的基本单位。我们可以理解为线程就是程序运行中的一条路径。

          多线程存在的意义

    允许多个线程并发执行,提高程序运行效率。

    例如:迅雷多线程下载,QQ多个人同时聊天,凌波多个人同时共享屏幕。

 线程的使用

         创建线程有两种方式

    自定义一个类继承Thread类,将线程要做的事写在run()方法中,由于子类可以当父类来用,创建自定义子类对象就是创建了一个线程。

    自定义一个类实现Runnable接口,将要做的事写在run()方法中。创建Thread对象时在构造函数中传入Runnable实现类对象。

         线程的启动

    两种创建方式都是调用Thread对象的start()方法。

    当调用start()方法时,CPU会开启一条新线程,并在新线程上执行run()方法。

 

public class ThreadDemo {

 public static void main(String[] args) {
//  demo1();
//  demo2();
 }

 private static void demo2() {
  MyRunnable r = new MyRunnable();  // 创建Runnable对象
  Thread t = new Thread(r);    // 创建Thread对象, 指定一个Runnable
  t.start();        // 开启线程, 会判断是否传入了Runnable, 传了就用Runnable的run()
  for (int i = 0; i < 100; i++)
   System.out.println("A: " + i);
 }

 private static void demo1() {
  MyThread t = new MyThread();
  t.start();        // 开启一条新线程, 该线程上会自动执行run()方法
  for (int i = 0; i < 100; i++)
   System.out.println("A: " + i);
 }

}

class MyRunnable implements Runnable{   // 定义一个类实现Runnable接口
 public void run() {       // 重写run()方法
  for (int i = 0; i < 100; i++)
   System.out.println("B: " + i);
 }
}

class MyThread extends Thread {     // 定义类继承Thread
 public void run() {       // 重写run()方法, 线程启动后就会运行run()方法
  for (int i = 0; i < 100; i++)
   System.out.println("B: " + i);
 }
}

 

 

   线程常用方法

    currentThread

静态方法,用来获取当前线程

    getName、setName

用来获取、设置当前线程的名字

    sleep

控制线程休眠,单位为毫秒

   setDaemon

将线程设置为守护线程。线程默认是非守护线程,守护线程不能单独执行。

    join

当前线程暂停,等待加入的线程运行结束,当前线程继续执行。

package cn.itcast.day19;

public class ThreadMethodDemo {

 public static void main(String[] args) {
//  demo1();
//  demo2();
//  demo3();
 }

 private static void demo3() {
  final Thread t1 = new Thread() {     
   public void run() {
    for (int i = 0; i < 10; i++){
     System.out.println(Thread.currentThread().getName() + " A: " + i);
     try {
      Thread.sleep(1000);   
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  };
  
  Thread t2 = new Thread(new Runnable(){  
   public void run() {
    for (int i = 0; i < 10; i++){
     System.out.println(Thread.currentThread().getName() + " B: " + i);
     try {
      if(i==3)
       t1.join();  // 当前线程暂停, 等待加入的线程运行结束, 当前线程再继续
      Thread.sleep(1000);   
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  });
  
  t1.start();
  t2.start();
 }

 private static void demo2() {
  Thread t1 = new Thread() {     
   public void run() {
    for (int i = 0; i < 10; i++){
     System.out.println(Thread.currentThread().getName() + " A: " + i);
     try {
      Thread.sleep(1000);   
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  };
  
  Thread t2 = new Thread(new Runnable(){  
   public void run() {
    for (int i = 0; i < 20; i++){
     System.out.println(Thread.currentThread().getName() + " B: " + i);
     try {
      Thread.sleep(1000);   
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  });
  
  Thread t3 = new Thread() {     
   public void run() {
    for (int i = 0; i < 5; i++){
     System.out.println(Thread.currentThread().getName() + " C: " + i);
     try {
      Thread.sleep(1000);   
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  };
  
  t1.setDaemon(true);  // 必须在开启之前设置
  t2.setDaemon(true);  // 将t2设置为守护线程, 不会单独运行. 有其他非守护线程运行该线程才运行
  
  t1.start();  // 10 setDaemon
  t2.start();  // 20 setDaemon
  t3.start();  // 5
 }

 private static void demo1() {
  Thread.currentThread().setName("主线程");
  System.out.println(Thread.currentThread().getName());  // 主线程 main
  
  Thread t1 = new Thread() {     // 定义Thread子类, 创建该类对象, 调用start()
   public void run() {
    for (int i = 0; i < 100; i++){
     System.out.println(Thread.currentThread().getName() + " A: " + i);
     try {
      Thread.sleep(1000);   // 线程休眠10毫秒
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  };
  
  Thread t2 = new Thread(new Runnable(){  // 定义Runnable实现类, 创建对象, 传入Thread构造函数, 调用start()
   public void run() {
    for (int i = 0; i < 100; i++){
     System.out.println(Thread.currentThread().getName() + " B: " + i);
     try {
      Thread.sleep(1000);   // 线程休眠10毫秒
     } catch (InterruptedException e) {
      e.printStackTrace();
     }  
    }
   }
  });
  
  t1.setName("线程1");
  t2.setName("线程2");
  
  t1.start();
  t2.start();
 }

}

 

 多线程同步

        线程安全问题

    多线程并发访问同一数据,有可能出现线程安全问题。

   一条线程的访问还没有结束,CPU切换到另一条线程工作,导致数据访问出错。

          使用同步解决线程安全问题

    使用同步代码块synchronized(锁对象){需要同步的代码...}形式将访问数据的代码锁住,在同步代码块中的内容同一时间内只能一个线程执行。

    使用同步方法,用synchronized修饰方法,整个方法的代码都是同步的,只能一个线程运行。同步方法使用this作为锁。

          死锁

   在多个线程并发执行使用多个锁来同步时,有可能互相冲突,导致程序无法继续执行。

         同步的优点与缺点

    同步可以解决多个线程同时访问一个共享数据的问题,只要加上同一个锁,在同一时间内只能有一条线程执行。

    在执行同步代码时每次都会判断锁,非常消耗资源,效率较低。

 

 

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.List;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;

public class Explorer {
 
 private Frame frame;
 private Panel panel;
 private TextField textField;
 private Button turnButton;
 private Button upButton;
 private List list;
 
 public Explorer(){
  createFrame();   // 创建窗体
  createPanel();   // 创建Panel, 包含地址栏, 2个按钮
  createList();   // 创建List
  
  handleEvent();
  
  frame.setVisible(true);
 }

 /*
  * 事件处理
  */
 private void handleEvent() {
  turnButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    turn();
   }
  });
  upButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    up();
   }
  });
  textField.addKeyListener(new KeyAdapter(){
   public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_ENTER)
     turn();
   }
  });
  list.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    click();
   }
  });
 }
 

 /*
  * 点击List
  *   获取选中的文本
  *   获取textField中的路径
  *   封装成一个File对象
  *   将textField中的路径设置为File对象的绝对路径
  *   跳转
  */
 private void click() {
  String name = list.getSelectedItem();
  String path = textField.getText();
  File file = new File(path, name);
  textField.setText(file.getAbsolutePath());
  turn();
 }
 
 /*
  * 跳转
  *   清除List中所有条目
  *   获取textFile中的文本
  *   封装成File对象
  *   如果File对象是文件, 就运行该文件
  *   如果是文件夹, 调用list()方法获取所有子文件名, 添加到List中
  */
 private void turn() {
  list.removeAll();
  String path = textField.getText();
  if (path != null && path.length() > 0) {
   File file = new File(path);
   if (file.isFile()) {
    if (file.getName().endsWith(".java") || file.getName().endsWith(".txt")) {
     new Notepad().loadFile(file);
    } else
     try {
      Runtime.getRuntime().exec("cmd /c \"" + file.getAbsolutePath() + "\"");
     } catch (IOException e) {
      throw new RuntimeException(e);
     }
   } else if (file.isDirectory()) {
    String[] names = file.list();
    for (String name : names)
     list.add(name);
   }
  }
 }
 
 /*
  * 向上
  *   获取textField中的文本
  *   封装成File对象
  *   获取父级路径
  *   设置回textField
  *   跳转
  */
 private void up() {
  String path = textField.getText();
  File file = new File(path);
  String parentPath = file.getParent();
  textField.setText(parentPath);
  turn();
 }
 
 

 /*
  * 创建Panel
  */
 private void createPanel() {
  // 创建Panel, 默认就是FlowLayout
  panel = new Panel();   
  
  // 创建文本框和按钮
  textField = new TextField(50); 
  turnButton = new Button("跳转");
  upButton = new Button("向上");
  
  // 将文本框和按钮添加到Panel
  panel.add(textField);
  panel.add(turnButton);
  panel.add(upButton);
  
  // 将Panel放在frame的北边
  frame.add(panel, BorderLayout.NORTH);
 }

 /*
  * 创建List
  */
 private void createList() {
  list = new List();
  frame.add(list);
 }

 /*
  * 创建窗体
  */
 private void createFrame() {
  frame = new Frame("资源管理器");
  frame.setSize(600, 400);
  frame.setLocation(200,200);
  frame.addWindowListener(new WindowAdapter(){
   public void windowClosing(WindowEvent e) {
    frame.dispose();
   }
  });
 }

 public static void main(String[] args) {
  new Explorer();
 }

}

 

 

 

 

 

多线程通信

    在同步代码中可以使用锁对象的wait()方法让当前线程等待

   使用锁对象的notify()方法可以将正在等待的线程唤醒

    如果多个线程都在等待,notify()唤醒随机1个

    notifyAll()方法可以唤醒所有在等待的线程

 

public class NotifyDemo {

 public static void main(String[] args) {
  final NotifyService service = new NotifyService();

  new Thread() {
   public void run() {
    for (int i = 0; i < 5; i++)
     service.print1();
   }
  }.start();

  new Thread() {
   public void run() {
    for (int i = 0; i < 5; i++)
     service.print2();
   }
  }.start();
  
  new Thread() {
   public void run() {
    for (int i = 0; i < 5; i++)
     service.print3();
   }
  }.start();
 }

}

class NotifyService {
 private int n = 1;
 private int flag = 1;  // 标识变量, 如果该值是1就轮到1, 是2就轮到2

 public void print1() {
  synchronized (this) {
   while(flag != 1)  // 如果不该1, 当前线程等待
    try {
     this.wait();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   for (int i = 0; i < 5; i++)
    System.out.println("线程1: " + n++);
   System.out.println();
   flag = 2;   // 该轮到2了
   this.notifyAll();  // 唤醒在该对象上等待的线程
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }

 public void print2() {
  synchronized (this) {
   while(flag != 2)  // 如果不该2, 当前线程等待
    try {
     this.wait();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   for (int i = 0; i < 5; i++)
    System.out.println("线程2: " + n++);
   System.out.println();
   flag = 3;   // 该轮到3了
   this.notifyAll();  // 唤醒在该对象上等待的线程
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
 
 public void print3(){
  synchronized (this) {
   while(flag != 3)  // 如果不该3, 当前线程等待
    try {
     this.wait();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   for (int i = 0; i < 5; i++)
    System.out.println("线程3: " + n++);
   System.out.println();
   flag = 1;   // 该轮到1了
   this.notifyAll();  // 唤醒在该对象上等待的线程
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
}

 

 

 JDK5之后的线程同步与通信

       同步

    使用java.util.concurrent.locks.Lock接口的实现类对象来进行同步

    ReentrantLock就是Lock的实现类,可以实现synchronized的功能

    在需要同步的代码块前后使用lock()和unlock()方法来完成同步

   unlock()最好放在finally中,因为如果上面代码抛出异常没有解锁的话,会导致其他线程无法运行,程序卡死。

 

import java.util.concurrent.locks.ReentrantLock;

public class SyncDemo {

 public static void main(String[] args) {
  final Service service = new Service();

  new Thread() {
   public void run() {
    while (true) {
     service.fun1();
    }
   }
  }.start();

  new Thread() {
   public void run() {
    while (true) {
     service.fun2();
    }
   }
  }.start();
 }

}

class Service {
 
 private ReentrantLock lock = new ReentrantLock();  // 创建锁对象
 
 public void fun1() {
  lock.lock();     // 开始同步
  try {
   System.out.print("闫");
   System.out.print("成");
   System.out.println("龙");
  } finally {
   lock.unlock();    // 结束同步
  }
 }

 public void fun2() {
  lock.lock();
  try {
   System.out.print("沙");
   System.out.print("诗");
   System.out.println("博");
  } finally {
   lock.unlock();
  }
 }
}

 

 

 

         通信

 使用Lock对象的newCondition()方法获取一个Condition对象,Condition对象可以控制指定线程的等待与唤醒。

  await()方法可以控制线程等待。

   signal()方法可以唤醒等待的线程。

 signalAll()方法可以唤醒所有等待线程。

 

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class NotifyDemo {

 public static void main(String[] args) {
  final NotifyService service = new NotifyService();

  new Thread() {
   public void run() {
    for (int i = 0; i < 5; i++)
     service.print1();
   }
  }.start();

  new Thread() {
   public void run() {
    for (int i = 0; i < 5; i++)
     service.print2();
   }
  }.start();
  
  new Thread() {
   public void run() {
    for (int i = 0; i < 5; i++)
     service.print3();
   }
  }.start();
 }

}

class NotifyService {
 private int n = 1;
 private int flag = 1; // 标识变量, 如果该值是1就轮到1, 是2就轮到2
 private ReentrantLock lock = new ReentrantLock();
 private Condition c1 = lock.newCondition();
 private Condition c2 = lock.newCondition();
 private Condition c3 = lock.newCondition();

 public void print1() {
  lock.lock();
  while(flag!=1)
   try {
    c1.await();       // 使用c1对象等待
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  for (int i = 0; i < 5; i++)
   System.out.println("线程1: " + n++);
  System.out.println();
  flag = 2;
  c2.signal();        // 指定唤醒c2对象
  lock.unlock();
 }

 public void print2() {
  lock.lock();
  while(flag!=2)
   try {
    c2.await();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  for (int i = 0; i < 5; i++)
   System.out.println("线程2: " + n++);
  System.out.println();
  flag = 3;
  c3.signal();
  lock.unlock();
 }

 public void print3() {
  lock.lock();
  while(flag!=3)
   try {
    c3.await();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  for (int i = 0; i < 5; i++)
   System.out.println("线程3: " + n++);
  System.out.println();
  flag = 1;
  c1.signal();
  lock.unlock();
 }
}

 

 

 

 

 

 

 

 

 

 

2.   GUI

  GUI概念       

   什么是GUI

 GUI是Graphical User Interface的缩写,图形化用户界面

          awt和swing

    Java为GUI提供的对象都存在java.awt,javax.swing两个包中

    awt依赖于本地系统平台,如颜色样式显示

    swing跨平台

         组件与容器

   组件 Component,是GUI图形界面的组成单元。

    容器Container,可以存放组件,也可以存放容器。

 

 

 布局管理

 

    FlowLayout(流式布局管理器)

    从左到右的顺序排列。

        BorderLayout(边界布局管理器)  

  东,南,西,北,中

          GridLayout(网格布局管理器)

   规则的矩阵

          CardLayout(卡片布局管理器)

    选项卡

      GridBagLayout(网格包布局管理器)

    非规则的矩阵

 

建立一个窗体

    窗体中可以存放各种组件,所以窗体是容器Container。创建时我们使用的是它的子类

   Container的常用子类有两个,Window和Panel。Window是我们常用的窗体,Panel是用来布局的不可见的。

   Window也有两个常用子类,Frame和Dialog。Frame是我们常用的带有标题和边框的顶层窗口,Dialog是对话框。

   所有AWT包中的类都会运行在AWT线程上

 

package cn.itcast.day20;

import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class FrameDemo {

 public static void main(String[] args) {
  Frame frame = new Frame("节日快乐!");
  frame.setSize(600, 400);
  frame.setLocation(200, 200); 
  frame.setLayout(new FlowLayout());
  Button button = new Button("关闭");
  frame.add(button);
  
  frame.addWindowListener(new MyWindowListener());   // 给frame添加窗体监听器  
  // button.addMouseListener(new MyMouseListener());   // 给button添加鼠标监听器
  // button.addKeyListener(new MyKeyListener());    // 给button添加键盘监听器
  button.addActionListener(new MyActionListener());   // 给button添加动作监听器
  
  frame.setVisible(true);          // 设置可见性. 也可以当做刷新用
 }

}

class MyActionListener implements ActionListener {  // 动作监听器
 public void actionPerformed(ActionEvent e) {
  Button button = (Button) e.getSource();
  Frame frame = (Frame) button.getParent();
  frame.dispose();
 }
}

class MyKeyListener extends KeyAdapter {    // 键盘监听器
 public void keyReleased(KeyEvent e) {
  if (e.getKeyCode() == KeyEvent.VK_SPACE) {  // 判断按下的键是空格
   Button button = (Button) e.getSource();
   Frame frame = (Frame) button.getParent();
   frame.dispose();
  }
 }
}

class MyMouseListener extends MouseAdapter {   // 鼠标监听器
 public void mouseClicked(MouseEvent e) {
  Button button = (Button) e.getSource();   // 获取事件源(Button)
  Frame frame = (Frame) button.getParent();  // 获取父级容器(Frame)
  frame.dispose();
 }
}

class MyWindowListener extends WindowAdapter {   // 窗体监听器
 public void windowClosing(WindowEvent e) {
  Frame frame = (Frame) e.getSource();   // 获取事件源, 强转为frame
  frame.dispose();        // 关闭窗体
 }
}

 

 

  事件处理

       事件处理机制

    事件:用户对组件的一个操作。

   事件源:发生事件的组件。

    监听器:我们需要处理某个事件,就需要在发生事件的组件上添加监听器,也就是java.awt.event包中XxxListener接口的子类。

    事件处理器:监听器中的方法。监听器被添加在组件上之后,组件上发生了对应事件就会执行指定方法。

          常用事件分类

   窗体事件,WindowEvent,窗体打开、关闭、正在关闭、激活、最小化等。

    鼠标事件,MouseEvent,鼠标按下、抬起、进入、移出等。

   键盘事件,KeyEvent,键盘按下、抬起等。

    动作事件,ActionEvent,在某一组件上发生了定义好的动作,例如按钮上鼠标点击或按空格,菜单上鼠标点击或按回车等。

         Adapter

    通常Listener接口中都是有多个抽象方法的,而我们使用的时候有可能不会全部需要,如果定义子类实现接口那么就必须重写所有方法,这是比较麻烦的。Java中为我们提供了一些抽象的实现类,在类中对接口的抽象方法进行了空的实现,我们再定义监听器时只要继承这些抽象类就可以,这样那些不需要的方法就可以不再去重写了。

 

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.List;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;

public class Explorer {
 
 private Frame frame;
 private Panel panel;
 private TextField textField;
 private Button turnButton;
 private Button upButton;
 private List list;
 
 public Explorer(){
  createFrame();   // 创建窗体
  createPanel();   // 创建Panel, 包含地址栏, 2个按钮
  createList();   // 创建List
  
  handleEvent();
  
  frame.setVisible(true);
 }

 /*
  * 事件处理
  */
 private void handleEvent() {
  turnButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    turn();
   }
  });
  upButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    up();
   }
  });
  textField.addKeyListener(new KeyAdapter(){
   public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_ENTER)
     turn();
   }
  });
  list.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    click();
   }
  });
 }
 

 /*
  * 点击List
  *   获取选中的文本
  *   获取textField中的路径
  *   封装成一个File对象
  *   将textField中的路径设置为File对象的绝对路径
  *   跳转
  */
 private void click() {
  String name = list.getSelectedItem();
  String path = textField.getText();
  File file = new File(path, name);
  textField.setText(file.getAbsolutePath());
  turn();
 }
 
 /*
  * 跳转
  *   清除List中所有条目
  *   获取textFile中的文本
  *   封装成File对象
  *   如果File对象是文件, 就运行该文件
  *   如果是文件夹, 调用list()方法获取所有子文件名, 添加到List中
  */
 private void turn() {
  list.removeAll();
  String path = textField.getText();
  if (path != null && path.length() > 0) {
   File file = new File(path);
   if (file.isFile()) {
    if (file.getName().endsWith(".java") || file.getName().endsWith(".txt")) {
     new Notepad().loadFile(file);
    } else
     try {
      Runtime.getRuntime().exec("cmd /c \"" + file.getAbsolutePath() + "\"");
     } catch (IOException e) {
      throw new RuntimeException(e);
     }
   } else if (file.isDirectory()) {
    String[] names = file.list();
    for (String name : names)
     list.add(name);
   }
  }
 }
 
 /*
  * 向上
  *   获取textField中的文本
  *   封装成File对象
  *   获取父级路径
  *   设置回textField
  *   跳转
  */
 private void up() {
  String path = textField.getText();
  File file = new File(path);
  String parentPath = file.getParent();
  textField.setText(parentPath);
  turn();
 }
 
 

 /*
  * 创建Panel
  */
 private void createPanel() {
  // 创建Panel, 默认就是FlowLayout
  panel = new Panel();   
  
  // 创建文本框和按钮
  textField = new TextField(50); 
  turnButton = new Button("跳转");
  upButton = new Button("向上");
  
  // 将文本框和按钮添加到Panel
  panel.add(textField);
  panel.add(turnButton);
  panel.add(upButton);
  
  // 将Panel放在frame的北边
  frame.add(panel, BorderLayout.NORTH);
 }

 /*
  * 创建List
  */
 private void createList() {
  list = new List();
  frame.add(list);
 }

 /*
  * 创建窗体
  */
 private void createFrame() {
  frame = new Frame("资源管理器");
  frame.setSize(600, 400);
  frame.setLocation(200,200);
  frame.addWindowListener(new WindowAdapter(){
   public void windowClosing(WindowEvent e) {
    frame.dispose();
   }
  });
 }

 public static void main(String[] args) {
  new Explorer();
 }

}

 

 

 

 

 

 

3.   Socket网络编程  

  IP地址

    每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址。

    ipconfig:查看本机IP

    ping:测试连接

    本地回路地址:127.0.0.1

    IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。已经用尽。 

  IPv6:8组,每组4个16进制数。

1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f

1a2b::aaaa:0000:0000:0000:aabb:1f2f

1a2b:0000:aaaa::aabb:1f2f

1a2b:0000:aaaa::0000:aabb:1f2f

1a2b:0000:aaaa:0000::aabb:1f2f

    

import java.net.*;
class IpDemo
{
 public static void main(String[] args) throws Exception
 {
  //获取本机ip对象。
  InetAddress ip = InetAddress.getLocalHost();

  System.out.println("ip="+ip);
  //单独获取名称和地址。
  System.out.println("address="+ip.getHostAddress());
  System.out.println("name="+ip.getHostName());


  //将主机名称或者ip地址字符串变成ip对象。
  InetAddress ia = InetAddress.getByName("192.168.1.109");

  System.out.println("ia address="+ia.getHostAddress());
  System.out.println("ia name="+ia.getHostName());

  System.out.println("----------------------------");

  InetAddress[] ip2 = InetAddress.getAllByName("www.baidu.com");
  System.out.println("ip2 address="+ip2[0].getHostAddress());
  System.out.println("ip2 name="+ip2[0].getHostName());


 }
}

 

 

端口号

 

    每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。

    端口号范围从0-65535

    编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。

    常用端口

mysql: 3306

oracle: 1521

web: 80

tomcat: 8080

QQ: 4000

feiQ: 2425

 

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Sender {

 public static void main(String[] args) throws Exception {
  // 要发送的数据
  byte[] data = "Hello 传智播客!".getBytes();
  
  // 创建DatagramSocket, 绑定本机IP, 绑定随机一个端口号
  DatagramSocket socket = new DatagramSocket();
  
  // 创建DatagramPacket, 包含要发送的数据, 数据长度, IP地址, 端口号
  DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), 8888);
  
  // 发送数据
  socket.send(packet);
  
  // 释放资源
  socket.close();
 }

}

 

         网络协议

  为计算机网络中进行数据交换而建立的规则、标准或约定的集合。

    UDP

面向无连接,数据不安全,速度快。不区分客户端与服务端。

    TCP

面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。

       Socket

 通信的两端都有Socket。

  网络通信其实就是Socket间的通信。

   数据在两个Socket间通过IO传输。

  Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。

 

 

 

 

 

 

UDP传输

      发送

    创建DatagramSocket

    创建DatagramPacket

   使用DatagramSocket发送DatagramPacket

    关闭DatagramSocket

      接收

   创建DatagramSocket

    创建DatagramPacket

    使用DatagramSocket接收DatagramPacket

   关闭DatagramSocket

 

import java.net.*;


//定义发送端,通过udp协议完成。
/*
用UDP发送数据。
思路:
1,建立一个UDPsocket服务。
2,定义要发送的数据。
3,将数据打成数据包。
4,通过socket服务将数据包发出去。
5,关闭资源。
*/
class  SendDemo
{
 public static void main(String[] args) throws Exception
 {
  //1,创建udpsocket服务。
  DatagramSocket ds = new DatagramSocket();

  //2,定义数据。
  String str = "udp demo ,o le ";
  byte[] buf = str.getBytes();

  //3,将数据打成数据包.
  DatagramPacket dp =
   new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000);

  //4,使用socket服务的send方法将数据发送出去。
  ds.send(dp);

  //5,关闭资源。
  ds.close();
 }
}

//使用了udp服务的接收端。
/*
建立UDP的接收端。
思路:
1,建立udpsocket服务。需要监听一个端口,简单说,就是给接收端这个应用程序定义一个数字标识。
2,定义数据包用于存储接收到的数据。
3,使用socket服务的接收功能,将数据都存储到数据包中。
4,通过数据包对象的方法获取具体的数据内容。
5,关闭资源。
*/
class ReceDemo
{
 public static void main(String[] args) throws Exception
 {
  //1,创建udpsocket服务,并监听一个端口
  DatagramSocket ds = new DatagramSocket(10000);

  //2,建立数据包,用于存储数据。存储时需要定义个字节数组缓冲区。
  byte[] buf = new byte[1024];

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

  //3,使用socket服务的receive方法将接收到的数据存储到数据包中。
  ds.receive(dp);

  //4,通过数据包对象的方法获取具体数据内容。
   //4.1获取地址。
   String ip = dp.getAddress().getHostAddress();

   //4.2获取端口
   int port = dp.getPort();
   //4.3获取数据。
   String data = new String(dp.getData(),0,dp.getLength());

   System.out.println(ip+"::"+data+"::"+port);
  //5,关闭资源。
  ds.close();
 }
}

 

 

TCP传输

         客户端

    创建Socket连接服务端

    调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的管道流

    输入流可以读取服务端输出流写出的数据

    输出流可以写出数据到服务端的输入流

         服务端

   创建ServerSocket

    调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket

    调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的管道流

   输入流可以读取客户端输出流写出的数据

    输出流可以写出数据到客户端的输入流

 

import java.net.*;
import java.io.*;

//建立tcp传输。
/*
创建客户端。
思路:
1,建立客户端socket服务。并同时指定要连接的服务端也就是指定ip和端口。
2,如果连接成功,就会有通道,就会有socket流。
 通过socket服务的方法可以获取其中的读写流对象。
3,通过读写流对象的读写方法将数据和服务端进行传输。
4,关闭资源。
需求:客户端发送一句话给服务端。
*/
class  ClientDemo
{
 public static void main(String[] args) throws Exception
 {
  //1,建立客户端socket服务。并指定要连接的ip和端口。
  Socket s = new Socket("192.168.1.254",10004);

  //2,通过socket服务的getOutputStream获取socket写入流对象。
  
  OutputStream out = s.getOutputStream();

  //3,将数据写到socket流中。
  out.write("tcp demo ,o le ".getBytes());

  s.close();
 }
}

/*
建立服务端:
思路:
1,建立服务端的socket服务。ServerSocket,服务端需要监听一个端口。
 给它分配一个数字标识。
2,获取具有socket流的Socket对象。
3,通过socket对象获取其中的流对数据进行操作。
4,关闭资源。
需求:服务端接收客户端的数据并打印即可。
*/
class  ServerDemo
{
 public static void main(String[] args) throws Exception
 {
  //1,建立服务端socket服务。并监听一个端口。
  ServerSocket ss = new ServerSocket(10004);

  //2,获取socket对象。
  Socket s = ss.accept();

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

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

  //3,通过socket对象获取socket读取流。

  InputStream in = s.getInputStream();

  byte[] buf = new byte[1024];

  int len = in.read(buf);

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

  System.out.println(str);

  s.close();
  ss.close();


 }
}

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值