网络编程

http://www.jd.com:80/index.html

URL(Uniform Resource Locator):统一资源定位符,它是指向互联网“资源”的指针。
组成部分:
  1.协议(http,https,ftp...),在://前面的部分
  2.主机域名部分: www.jd.com 192.168.1.23
  3.端口部分:80
  4.资源路径(资源名称): index.html /test/index.html
java.net.URL
  构造函数:
    URL(String spec)根据 String 表示形式创建 URL 对象。
      URL url = new URL("http://www.jd.com:80/test/index.html");
    URL(String protocol, String host, int port, String file)根据指定 protocol、host、port 号和 file 创建 URL 对象。
      URL url = new URL("http","www.jd.com",80,"/test/index.html");
  常用的方法:
    getHost()获取此 URL 的主机名(如果适用)。
    getFile() 获取此 URL 的文件名。
    getPort() 获取此 URL 的端口号。
    getProtocol()获取此 URL 的协议名称。
    openStream()打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。

public class TestURL {
    public static void main(String[] args) {
        try {
            URL url = new URL("http://www.jd.com:8080/test/index.html");
            String protocol = url.getProtocol();
            System.out.println("协议名称:"+protocol);
            String host = url.getHost();
            System.out.println("主机域名:"+host);
            int port = url.getPort();
            System.out.println("端口号:"+port);
            int defaultPort = url.getDefaultPort();
            System.out.println("默认端口:"+defaultPort);
            String file = url.getFile();
            System.out.println("文件路径:"+file);
            System.out.println("---------读取京东主页内容-----------");
            URL jingdong = new URL("https://www.jd.com/index.html"); 
            InputStream  ips = jingdong.openStream();
            InputStreamReader isr = new InputStreamReader(ips,"UTF-8");//将字节流转换为字符流
            BufferedReader br = new BufferedReader(isr);
            String str;
            while((str=br.readLine())!=null){
                System.out.println(str);
            }
            br.close();
            isr.close();
            ips.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

java.lang.*:java的核心类
java.util.*:工具包
java.text.*:格式化输出的类 (SimpleDataFormat)
java.io.*:保存与IO流操作相关类和接口
java.net.*:保存与网络通信相关类和接口
IPv4地址是有32为二进制组成,IPv6是128为的二进制组成,用于表示唯一表示网络上的计算机
端口号:用于表示一台计算机上不同的服务,取值范围0~66535
 0~1023系统服务占用
 常用的端口:
   ftp的端口号:21
   www服务器:80
   oracle:1521
  mysql:3306
  sqlserver:1433
java.net.InetAddress类:此类表示互联网协议 (IP) 地址。 没有端口
构造函数:没有
常用方法:
  获取InetAddress对象的方法
   getByName(String host)在给定主机名的情况下确定主机的 IP地址。
  getAllByName(String host) 在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
  getLocalHost():返回本地主机。
实例方法:
  getHostName() 获取此 IP 地址的主机名。

  getHostAddress() 返回 IP 地址字符串(以文本表现形式)。
  toString() 将此 IP 地址转换为 String。 主机名/IP地址

public class TestInetAddress {
    public static void main(String[] args) {
        try {
            InetAddress  inetAddress = InetAddress.getLocalHost();//获取本机IP地址
            System.out.println(inetAddress);//2013-20161115CZ/192.168.1.47
            InetAddress inetAddress2 = InetAddress.getByName("LY");//根据主机名获取IP地址
            System.out.println(inetAddress2);
            InetAddress inetAddress3 = InetAddress.getByName("www.baidu.com");//根据主机名获取IP地址
            System.out.println(inetAddress3);
            InetAddress[] inetAddresses =  InetAddress.getAllByName("www.qq.com");
            for (InetAddress inetAddress4 : inetAddresses) {
                String hostName = inetAddress4.getHostName();
                System.out.println("主机名:"+hostName);
                String hostAddress = inetAddress4.getHostAddress();
                System.out.println("IP地址:"+hostAddress);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

java.net.InetSocketAddress:此类实现 IP套接字地址(IP 地址 + 端口号)。主要用于Socket编程
  构造函数:
    InetSocketAddress(InetAddress addr, int port) 根据 IP 地址和端口号创建套接字地址。
    InetSocketAddress(int port) 创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。
    InetSocketAddress(String hostname, int port) ** 根据主机名和端口号创建套接字地址。
  常用方法:
    getAddress()获取 InetAddress。
    getPort()获取端口号。
    getHostName() 获取 hostname。

public class TestInetSocketAddress {
    public static void main(String[] args) {
        //本机
        InetSocketAddress  inetSocketAddress = new InetSocketAddress("127.0.0.1",8888);
        String hostName = inetSocketAddress.getHostName();
        int port = inetSocketAddress.getPort(); 
        System.out.println("hostName:"+hostName);
        System.out.println("Port:"+port);
        //淘宝
        try {
            InetAddress  inetAddress = InetAddress.getByName("www.taobao.com");
            InetSocketAddress  remoteAddress = new InetSocketAddress(inetAddress,80);
            String remoteHostName = remoteAddress.getHostName();
            int remotePort = remoteAddress.getPort();
            System.out.println(remoteHostName+"---"+remotePort);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

Socket(套接字):套接字是两台机器间通信的端点。
java.net.Socket
  常用的构造函数:
    Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
    Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
  常用方法:
    getOutputStream() 返回此套接字的输出流。
    getInputStream() 返回此套接字的输入流
    close(): 关闭此套接字。
客户端发送数据的步骤:
  1.创建一个和服务器端通信的套接字
    Socket socket = new Socket("127.0.0.1",8888);
  2.使用套接字获取一个输出流
    OutputStream ops = socket.getOutputStream();//
  3.使用输出流发送数据

public class HelloClient {
    public static void main(String[] args) {
//        InetAddress localhost = InetAddress.getByName("127.0.0.1");
//        Socket socket = new Socket(localhost, 8888);
        Socket socket=null;
        OutputStream ops=null;
        OutputStreamWriter osw=null;
        try {
            //1.创建一个套接字(127.0.0.1:服务器端的地址,8888:服务器端口)
            socket = new Socket("127.0.0.1",8888);
            //2.从套接字中获取输出流,用于输出数据
            ops = socket.getOutputStream();//
            osw = new OutputStreamWriter(ops);
            osw.write("客户端---->长江长江,我是黄河!");
            osw.flush();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                osw.close();
                ops.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务器端读取的步骤:
  1.创建一个服务器端的套接字:
    ServerSocket serverSocket = new ServerSocket(8888);
  2.调用服务器端套接字的accept(),侦听并接受到此套接字的连接。
    Socket socket = serverSocket.accept();
  3.通过套接字getInputStream方法获取输入流。
    InputStream ips = socket.getInputStream();
  4.同输入流读取数据
  ...
java.net.ServerSocket类:此类实现服务器套接字
  构造函数:
    ServerSocket(int port)创建绑定到特定端口的服务器套接字。
  常用方法:
    accept()侦听并接受到此套接字的连接。

public class HelloServer {
    public static void main(String[] args) {
        try {
            //1.创建服务器端套接字,其中参数8888为服务器的端口号
            ServerSocket  serverSocket = new ServerSocket(8888);
            //2.调用accept()方法,侦听并接受到此套接字的连接。
            Socket  socket = serverSocket.accept();
            //3.通过getInputStream()获取一个套接字输入流,用于读取数据
            InputStream ips = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(ips);
            BufferedReader br = new BufferedReader(isr);
            String str = br.readLine();
            System.out.println("服务器端收到的消息:"+str);
            //4.关闭资源
            br.close();
            isr.close();
            ips.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 双向通信
 * 客户端:
 * 
 */
public class SimpleClient {
    public static void main(String[] args) {
        System.out.println("客户端启动了....");
        try {
            Socket  socket = new Socket("127.0.0.1",6666);
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            DataInputStream  dis = new DataInputStream(socket.getInputStream());
            dos.writeUTF("hello, i am client!");
            dos.flush();
            String message = dis.readUTF();
            System.out.println(message);
            //释放资源
            dos.close();
            dis.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}
 
public class SimpleServer {
    /**
     * 服务器端
     * @param args
     */
    public static void main(String[] args) {
        try {
            System.out.println("服务器端启动了.....");
            ServerSocket serverSocket = new ServerSocket(6666);
            Socket socket = serverSocket.accept();
            DataInputStream  dis = new DataInputStream(socket.getInputStream());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            String message = dis.readUTF();
            System.out.println(message);
            dos.writeUTF("hello ,i am server!");
            dis.close();
            dos.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

登录:

/**
 * User实体对象:用于封装用户信息
 * @author Administrator
 */
public class User implements Serializable {
    private String username;
    private String password;
    
    public User() {
        super();
    }

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    
    
}
public class LoginClient {
    public static void main(String[] args) {
        System.out.println("------客户端------");
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = input.next();
        System.out.println("请输入密码:");
        String password = input.next();
        User user = new User(username,password);//将用户名和密码封装到user对象中
        try {
            //1.创建一个Socket对象
            Socket socket = new Socket("127.0.0.1",8888);
            //2.创建对象输出流,用于输出user对象
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(user);
            oos.flush();
            
            //接受服务器的数据
            //3.创建DataInputStream对象,用于读取服务器端响应的消息
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            //读取消息
            String message = dis.readUTF();
            System.out.println(message);
            //关闭流和socket
            oos.close();
            dis.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        
    }
}
public class LoginServer {
    public static void main(String[] args) {
        System.out.println("------服务器端------");
        try {
            //1.创建ServerSocket对象
            ServerSocket serverSocket = new ServerSocket(8888);
            //2.调用accept()方法,返回Socket
            Socket socket = serverSocket.accept();
            //3.创建对象输入流,用于读取客户端发送的数据
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            User user = (User)ois.readObject();
            //4.判断用户名和密码是否正确
            String message;
            if("zzsxt".equals(user.getUsername())&&"123456".equals(user.getPassword())){
                message="欢迎您,登陆成功!";
            }else{
                message="用户名或密码有误,请重新登陆!";
            }
            //4.创建DataOutputStream对象,将message消息输出到客户端
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            dos.writeUTF(message);
            dos.flush();
            //5.关闭socket和流
            ois.close();
            dos.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

上传的客户端:
1.使用输入流将D:/mp3/test.mp3读取
2.使用套接字中输出流将D:/mp3/test.mp3输出
3.使用套接字的输入流读取服务器端反馈的消息

使用缓冲流(BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter)
Socket的shutdownOutput()方法关闭输出流,这样对端的输入流上的read操作就会返回-1,避免阻塞

public class UploadClient {
    public static void main(String[] args) throws Exception{
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/mp3/test.mp3"));
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        int len;
        //使用缓冲字节输入流读取
        while((len=bis.read())!=-1){
            bos.write(len);//使用缓冲字节输出流写入Socket
        }
        bos.flush();
        socket.shutdownOutput();
        System.out.println("客户发送完毕!");
        DataInputStream dis  = new DataInputStream(socket.getInputStream());
        String message = dis.readUTF();
        System.out.println(message);
        
        bis.close();
        bos.close();
        dis.close();
        socket.close();
    }
}

1.使用套接字的输入流将文件读取出来
2.使用输出流将从套接字中读取的内容写入到指定位置
3.使用套接字的输出流向客户端输出反馈消息

public class UploadServer {
    public static void main(String[] args) throws Exception{
        ServerSocket  serverSocket = new ServerSocket(8888);
        Socket socket = serverSocket.accept();
        //用于读取客户端发送的文件数据
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F:/test.mp3"));
        int len;
        while((len=bis.read())!=-1){
            bos.write(len);
        }
        bos.flush();
        System.out.println("服务器端文件接受完毕!");
        //获取套接字的输出流,用于向客户端发送反馈消息
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); 
        dos.writeUTF("服务器端接受完毕!");
        dos.flush();
        
        bis.close();
        bos.close();
        dos.close();
        socket.close();
        serverSocket.close();
     }
}
    private String username;
    private String password;
    
    public User() {
        super();
    }

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }
    
    
}
public class LoginServer {
    //用于保存用户名和密码,用户名做键,密码做值
    static Map<String,String> map = new HashMap<String,String>();
    //使用静态块进行初始化
    static{
        map.put("zzsxt", "zzsxt");
        map.put("bjsxt", "bjsxt");
        map.put("shsxt", "shsxt");
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println("------服务器端------");
        //1.创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(8888);
        int count=0;
        while(true){
            Socket socket = serverSocket.accept();//监听客户端请求,并返回一个套接字
            //使用对象输入流读取客户端发送的数据
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            User user = (User)ois.readObject();
            //获取用户名和密码
            String uname = user.getUsername();// whsxt
            String upass = user.getPassword(); //123
            //根据客户端用户输入的用户名进行查找
            String password = map.get(uname);
            if(upass.equals(password)){//密码相同
                dos.writeUTF("登陆成功!
欢迎您,!"+uname);
            }else{
                dos.writeUTF("用户名或密码有误,请重新输入!");
            }    
            System.out.println("第"+(++count)+"位访客,用户信息:"+user);
            dos.flush();
            //关闭资源
            ois.close();
            dos.close();
            socket.close();
        }
    }
}
public class LoginClient {
    public static void main(String[] args) {
        System.out.println("------客户端------");
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = input.next();
        System.out.println("请输入密码:");
        String password = input.next();
        User user = new User(username,password);//将用户名和密码封装到user对象中
        try {
            //1.创建一个Socket对象
            Socket socket = new Socket("127.0.0.1",8888);
            //2.创建对象输出流,用于输出user对象
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(user);
            oos.flush();
            
            //接受服务器的数据
            //3.创建DataInputStream对象,用于读取服务器端响应的消息
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            //读取消息
            String message = dis.readUTF();
            System.out.println(message);
            //关闭流和socket
            oos.close();
            dis.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        
    }
}
利用多线程实现同时处理多个用户请求:为每一个客户端的请求单独创建一个线程
public class User implements Serializable {
    private String username;
    private String password;
    
    public User() {
        super();
    }

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }
    
    
}
/**
 *HashMap与Hashtable的区别
 *1.HashMap是非线程安全,而Hashtable是线程安全的适合在多线程中使用 
 *2.HashMap键和值都可以为null,Hashtable则不然
 */
public class LoginThread extends Thread{
    private Socket socket;
    
    public LoginThread(Socket socket){
        this.socket=socket;
    }
    static int count=0;//计数
    //用于保存用户名和密码,用户名做键,密码做值
    static Map<String,String> map = new Hashtable<String,String>();
    //使用静态块进行初始化
    static{
        map.put("zzsxt", "zzsxt");
        map.put("bjsxt", "bjsxt");
        map.put("shsxt", "shsxt");
    }
    
    @Override
    public void run() {
        try {
            //使用对象输入流读取客户端发送的数据
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            User user = (User)ois.readObject();
            //获取用户名和密码
            String uname = user.getUsername();// whsxt
            String upass = user.getPassword(); //123
            //根据客户端用户输入的用户名进行查找
            String password = map.get(uname);
            if(upass.equals(password)){//密码相同
                dos.writeUTF("登陆成功!
欢迎您,!"+uname);
            }else{
                dos.writeUTF("用户名或密码有误,请重新输入!");
            }    
            System.out.println("第"+(++count)+"位访客,用户信息:"+user);
            dos.flush();
            //关闭资源
            ois.close();
            dos.close();
            socket.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/**
 *客户端
 */
public class LoginClient {
    public static void main(String[] args) {
        System.out.println("------客户端------");
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = input.next();
        System.out.println("请输入密码:");
        String password = input.next();
        User user = new User(username,password);//将用户名和密码封装到user对象中
        try {
            //1.创建一个Socket对象
            Socket socket = new Socket("127.0.0.1",8888);
            //2.创建对象输出流,用于输出user对象
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(user);
            oos.flush();
            
            //接受服务器的数据
            //3.创建DataInputStream对象,用于读取服务器端响应的消息
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            //读取消息
            String message = dis.readUTF();
            System.out.println(message);
            //关闭流和socket
            oos.close();
            dis.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        
    }
}
/**
 * 单线程存在的问题:当多个用户同时访问时,用户只能按照访问顺序进行等待。
 * 解决方案:
 * 利用多线程实现同时处理多个用户请求:为每一个客户端的请求单独创建一个线程
 * 
 */
public class LoginServer {

    
    public static void main(String[] args) throws Exception {
        System.out.println("------服务器端------");
        //1.创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(8888);
        int count=0;
        while(true){
            Socket socket = serverSocket.accept();//监听客户端请求,并返回一个套接字
            LoginThread loginThread = new LoginThread(socket);
            //启动线程
            loginThread.start();
        }
    }
}
/**
 * 聊天的客户端
 */
public class ChartClient {
    public static void main(String[] args) throws Exception{
//        InputStreamReader isr = new InputStreamReader(System.in);//将键盘输入的内容转为字符流 System.in:标准输入流
//        BufferedReader input = new BufferedReader(isr);
        Scanner input = new Scanner(System.in);
        Socket socket = new Socket(InetAddress.getLocalHost(),6666);
        //获取套接字中输入流,用于读取服务器端的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //获取套接字中输出流,用于发送客户端的数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        while(true){
            //获取用户输入
//            String clientMessage = input.readLine();
            String clientMessage = input.nextLine();
            //如果客户端输入内容为end的话,结束会话.
            if("end".equals(clientMessage)){
                break;
            }
            //将客户的消息输出
            bw.write(clientMessage+"
");// 
必须添加,防止服务器端使用readLine()方法读取时阻塞
            bw.flush();
            //获取服务器的消息
            String serverMessage = br.readLine();
            if(serverMessage!=null){
                System.out.println("服务器端说:"+serverMessage);
            }
        }
        //关闭流和套接字
        br.close();
        bw.close();
        socket.close();
    }
}
/**
 * 聊天的服务器端
 */
public class ChartServer {
    public static void main(String[] args) throws Exception{
        Scanner input = new Scanner(System.in);
        //创建ServerSocket对象,并指定监听端口6666
        ServerSocket serverSocket = new ServerSocket(6666);
        //监听6666端口,并返回一个套接字
        Socket socket = serverSocket.accept();
        //获取套接字中输入流,用于读取客户端的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //获取套接字中输出流,用于发送服务器端的数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        while(true){
            //获取客户端的数据
            String clientMessage = br.readLine();
            if(clientMessage!=null){
                System.out.println("客户端说:"+clientMessage);
            }
            //获取用户输入
            String serverMessage = input.nextLine();
            //如果服务器端输入内容为end的话,结束会话.
            if("end".equals(serverMessage)){
                break;
            }
            //将客户的消息输出
            bw.write(serverMessage+"
");// 
必须添加,防止服务器端使用readLine()方法读取时阻塞
            bw.flush();
        }
        //关闭流和套接字
        br.close();
        bw.close();
        socket.close();
    }
}

单项一次通信:
客户端:顾客
单项通信:顾客--->客服发送消息--->客服获取消息并展示
java.net.DatagramSocket:此类表示用来发送和接收数据报包的套接字。 (发送电报的电台)
  作用:发送和接受数据报包
  构造函数:
    DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。
    DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。
  常用方法:
    send(DatagramPacket p)从此套接字发送数据报包。
    receive(DatagramPacket p)从此套接字接收数据报包。
    close() 关闭此数据报套接字。

java.net.DatagramPacket:此类表示数据报包。 类似于信封(封装信和收件人地址信息)
  作用:用于封装内容数据和目的地的地址
  构造函数:
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)
  构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

public class AskClient {
    public static void main(String[] args) throws Exception{
        //1.创建数据报包的套接字DatagramSocket
        DatagramSocket datagramSocket = new DatagramSocket();
        String str="亲,在吗?";
        byte[] content =str.getBytes();
        InetAddress inetAddress = InetAddress.getLocalHost();
        //2.创建数据报包:包含有内容,发送内容的长度,目的地IP,目的地的端口
        DatagramPacket datagramPacket = new DatagramPacket(content,content.length,inetAddress,6666);
        //3.使用send方法发送数据报包
        datagramSocket.send(datagramPacket);
        //4.关闭套接字
        datagramSocket.close();
    }
}


服务器端:客服
java.net.DatagramPacket:数据报包用来实现无连接包投递服务
  构造函数:
    DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)
  构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
  常用方法:
    getAddress() 获取发送方的IP地址
    getData() 返回数据缓冲区。
    getPort() 获取端口
    getLength() 返回将要发送或接收到的数据的长度。

public class AskServer {
    public static void main(String[] args) throws Exception{
        //1.创建一个数据报套接字
        DatagramSocket datagramSocket = new DatagramSocket(6666);
        //2.创建一个数据报包
        byte[] content = new byte[1024];
        DatagramPacket datagramPacket =  new DatagramPacket(content, content.length);
        //3.调用套接字的receive接收数据报包
        datagramSocket.receive(datagramPacket);
        //4.从数据报包中获取数据
        InetAddress inetAddress=datagramPacket.getAddress();
        byte[] data = datagramPacket.getData();
        int port = datagramPacket.getPort();
        int length = datagramPacket.getLength();
        System.out.println("访问者IP地址:"+inetAddress);
        System.out.println("内容:"+new String(data,0,length));
        System.out.println("访问者端口:"+port);
        System.out.println("长度:"+length);
        //5.关闭套接字
        datagramSocket.close();
    }
}

双向一次通信

public class AskClient {
    public static void main(String[] args) throws Exception{
        //1.创建数据报包的套接字DatagramSocket
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        String str="亲,在吗?";
        byte[] content =str.getBytes();
        InetAddress inetAddress = InetAddress.getLocalHost();
        //2.创建数据报包:包含有内容,发送内容的长度,目的地IP,目的地的端口
        DatagramPacket datagramPacket = new DatagramPacket(content,content.length,inetAddress,6666);
        //3.使用send方法发送数据报包
        datagramSocket.send(datagramPacket);
        
        //接收消息
        byte[] content2 = new byte[1024];
        DatagramPacket  datagramPacket2 = new DatagramPacket(content2, content2.length);
        datagramSocket.receive(datagramPacket2);
        byte[] data = datagramPacket2.getData();
        System.out.println("客服说:"+new String(data,0,data.length));
        //4.关闭套接字
        datagramSocket.close();
        
        
    }
}
public class AskServer {
    public static void main(String[] args) throws Exception{
        //1.创建一个数据报套接字
        DatagramSocket datagramSocket = new DatagramSocket(6666);
        //2.创建一个数据报包
        byte[] content = new byte[1024];
        DatagramPacket datagramPacket =  new DatagramPacket(content, content.length);
        //3.调用套接字的receive接收数据报包
        datagramSocket.receive(datagramPacket);
        //4.从数据报包中获取数据
        InetAddress inetAddress=datagramPacket.getAddress();
        byte[] data = datagramPacket.getData();
        System.out.println("顾客说:"+new String(data,0,data.length));
         //发送消息
        String str2 = "亲,在的!";
        byte[] content2 = str2.getBytes();
        DatagramPacket datagramPacket2 = new DatagramPacket(content2, content2.length,InetAddress.getByName("localhost"),8888);
        datagramSocket.send(datagramPacket2);
        datagramSocket.close();
    }
}

利用UDP实现多次双向交互
多次双向

UDP和TCP通信的区别
1.是否面向连接:TCP是面向连接,点对点的通信, 而UDP是非连接的
2.可靠性:TCP传输数据内容可靠,而UDP数据的顺序无法确定,不可靠
3.传输大小:TCP无限制,UDP单包的传输大小限制在64K以内。
4.传输效率: UDP>TCP

public class UdpClient {
    public static void main(String[] args) throws Exception{
        Scanner input = new Scanner(System.in);
        //1.创建数据报套接字
        DatagramSocket datagramSocket = new DatagramSocket(6666);
        while(true){
            String content = input.nextLine();
            byte[] bs = content.getBytes();
            //2.创建数据报包
            DatagramPacket datagramPacket = new DatagramPacket(bs, bs.length, InetAddress.getLocalHost(), 8888);
            //3.发送数据
            datagramSocket.send(datagramPacket);
            if("bye".equals(content)){
                break;
            }
            //4.接受数据报包
            byte[] bs2 = new byte[1024];
            DatagramPacket datagramPacket2 = new DatagramPacket(bs2, bs2.length);
            datagramSocket.receive(datagramPacket2);
            //5.获取数据报包中数据
            byte[] data = datagramPacket2.getData();
            System.out.println("客服说:"+new String(data,0,data.length));
        }
        //6.关闭套接字
        datagramSocket.close();
    }
}
/**
 * 客服
 * @author Administrator
 *
 */
public class UdpServer {
    public static void main(String[] args) throws Exception{
        Scanner input = new Scanner(System.in);
        //1.创建数据报套接字
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        while(true){
            //2.接受数据报包
            byte[] bs2 = new byte[1024];
            DatagramPacket datagramPacket2 = new DatagramPacket(bs2, bs2.length);
            datagramSocket.receive(datagramPacket2);
            //3.获取数据报包中数据
            byte[] data = datagramPacket2.getData();
            System.out.println("顾客说:"+new String(data,0,data.length));
            
            String content = input.nextLine();
            byte[] bs = content.getBytes();
            //4.创建数据报包
            DatagramPacket datagramPacket = new DatagramPacket(bs, bs.length, InetAddress.getLocalHost(), 6666);
            //5.发送数据
            datagramSocket.send(datagramPacket);
            if("bye".equals(content)){
                break;
            }
            
        }
        //6.关闭套接字
        datagramSocket.close();
    }
}
原文地址:https://www.cnblogs.com/fwdsz/p/6792702.html