网络编程

网络编程就是通过网络协议在多个计算机网络连接进行通信。

java.net 包中提供了两种常见的网络协议的支持:

  • TCP:TCP 是通过建立连接,进行通信的安全的网络协议,被称 TCP / IP,安全但效率比较低。

  • UDP:UDP 一个无连接的协议。应用程序之间通过发送数据包进行通信,可能会丢包,不安全但效率高。

UDP

UDP协议编程。

服务端

1,首先需要通过DatagramSocket绑定本地的一个端口,绑定后其他计算机才能通过本机IP地址加端口来访问。

2,接受数据,UDP编程都是通过发送包裹来传输信息,所以需要准备一个包裹容器,通过DatagramPacket类建立一个发送或接受信息的包裹

  接收数据包,这是一个接受的包裹,所以只需要指定多少大小的包裹就可以了

  public DatagramPacket(byte[] buf,int length)

  

  发送数据包发送的包裹还需要指定发送的IP和端口

  public DatagramPacket(byte[] buf,int offset,int length,SocketAddress address)

  buf - 分组数据。offset - 分组数据偏移。length - 分组数据长度。address - 目标套接字地址(包含类目标IP和端口)

需要注意的是:UDP的包裹都需要通过字节数组进行构建,所以其它的基本类型,对象,文件的传输都需要先转化为字节数组,如何转换后面在讲;

3,接受包裹,通过receive()方法接收,这个方法是阻塞式的,只要接收到包裹后,程序才会向下执行。

4,分析包裹,通过getData()方法获取包裹字节数组数据,接收的肯定是字节数组,所以需要通过字节数组获取数据:  

 byte[] datas=packet.getData();

 

代码:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpServer {
    public static void main(String args[]) throws Exception {
        System.out.println("接受方启动......");
        //1、使用DataframSocket类对象 传入参数指定本地接受端口
        DatagramSocket server = new DatagramSocket(6666);
        //2、准备容器 封装成DatagramPacket包裹
        byte[] container = new byte[1024*60];
        DatagramPacket packet = new DatagramPacket(container,0,container.length);
        //3、阻塞式接受包裹receive(DatagramPacket p)
        server.receive(packet);
        //4、分析数据
        //   byte[] getData()
        //          getLength()
        byte[] datas=packet.getData();
        int len = packet.getLength();
        System.out.println(new String(datas,0,len));
        server.close();
    }
}

客户端:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class UdpClient {
    public static void main(String args[]) throws Exception {
        System.out.println("发送方启动中......");
        //1,绑定本地端口,用于发送接收消息
        DatagramSocket client= new DatagramSocket(8888);
        //2,构建数据包
        String data="我爱北京天安门";
        byte[] datas=data.getBytes();
        DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
     //发送数据包 client.send(packet); client.close(); } }

 

如何转换基本类型,文件,对象为字节数组
通过java的IO流,管道流转换;

1,基本类型转换为字节数组;

     DatagramSocket client= new DatagramSocket(8888);
        //1,ByteArrayOutputStream是字节数组流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
     //2,给baos字节数组流外面接一个基本类型数据流DataOutputStream就可以通过dos写入基本类型数据,baos流出字节数组了 DataOutputStream dos
= new DataOutputStream(new BufferedOutputStream(baos)); //3,写入基本类型数据 dos.writeUTF("编码辛酸泪"); dos.writeInt(18); dos.writeBoolean(false); dos.writeChar('a'); dos.flush();
     //4,通过toByteArray()方法将当前管道的缓存数据返回成字节数组
byte[] datas=baos.toByteArray(); DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666)); client.send(packet); client.close();

2,对象转换为字节数组

  对象的转换需要通过ObjectOutputStream或ObjectInputStream来发送和接收对象。为了能够进行传输,这些对象必须是可序列化的(可序列化的对象,它实例化它的类必须实现Serializable接口)。

3,文件转换为字节数组

其实就是通过文件流不断读取数据,写到字节输出流,保存到字节数组中,创建包裹,然后发送;

package net;

import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class UdpobjClient {
    public static void main(String args[]) throws Exception {
        System.out.println("发送方启动中......");
        //1、使用DatagramSocket指定端口,创建发送端
        DatagramSocket client= new DatagramSocket(8888);
        //2、准备数据 一定转成字节数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
        //操作数据类型+数据
        File file=new File("src/net/img.png");
        byte[] datas=FileToArray(file);
        DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
        client.send(packet);
        client.close();
    }
    private static byte[] FileToArray(File file) throws IOException {
        byte[] data=null;
        try {
            FileInputStream fis= new FileInputStream(file);
            ByteArrayOutputStream baos= new ByteArrayOutputStream();
            
            int len;
            byte[] buffer = new byte[1024];
            while((len=fis.read(buffer))!=-1) {
                baos.write(buffer,0,len);
            }
            data=baos.toByteArray();
            fis.close();
            baos.close();
        } catch (FileNotFoundException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        return data;
    }
}
View Code

如何建立两台同时发送接收消息

加入多线程,将发送端和接收端封装成线程,需要连接就直接开始一个线程,这样就可以同时与多台设备通信了;

import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class UdpSend implements Runnable{
    private int port;
    DatagramSocket client;
    BufferedReader in;
    DatagramPacket packet;
    String toIP;
    int toPort;
    String data = null;
    UdpSend(int port,String toIP,int toPort) throws Exception{
        this.toIP=toIP;
        this.toPort=toPort;
        client= new DatagramSocket(port);
        in= new BufferedReader(new InputStreamReader(System.in)); 
    }
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        while(true) {
            try {
                data = in.readLine();
                byte[] datas=data.getBytes();
                packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(toIP,toPort));
                client.send(packet);
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            if(data.equals("bye")) {
                break;
            }
        }
        client.close();
    }
    
}
发送端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpReceive implements Runnable{
    DatagramSocket server;
    byte[] container;
    DatagramPacket packet;
    String data;
    UdpReceive(int port) throws SocketException{
        server = new DatagramSocket(port);
        container= new byte[1024*60];
        packet = new DatagramPacket(container,0,container.length);
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        while(true) {
            try {
                server.receive(packet);
                byte[] datas=packet.getData();
                int len = packet.getLength();
                data=new String(datas,0,len);
                System.out.println(data);
                if(data.equals("bye")) {
                    break;
                }
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }    
        }    
        server.close();
    }
}
接收端

学生与老师同时发送接收消息;

学生:


public class Student {
  public static void main(String args[]) throws Exception {
    new Thread(new UdpSend(8888,"localhost", 9999)).start();
    new Thread(new UdpReceive(7777)).start();
  }
}  

 老师:

public class Teacher {
    public static void main(String args[]) throws Exception {
        new Thread(new UdpSend(5555,"localhost", 7777)).start();;
        new Thread(new UdpReceive(9999)).start();;
    }
}

 

TCP

TCP协议分为服务端和客户端,两端的部署有一点不一样;

服务端:

1,服务器实例化一个 ServerSocket 对象,绑定一个端口,用来监听客户端连接;

2,服务器调用 ServerSocket 类的 accept() 方法,该方法将一直阻塞式等待,直到客户端连接到服务器上给定的端口,返回一个Socket对象;

3,通过socket的getInputStream()和getOutputStream()获得与客户端连接的输入输出流,进行通信;

客户端:

1,通过Socket实例化一个与指定主机和端口的服务器连接;

2,通过socket的getInputStream()和getOutputStream()获得与服务器端连接的输入输出流,进行通信;

代码:

服务器:

 

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

public class server {
    public static void main(String args[]) throws IOException {
        ServerSocket server = new ServerSocket(8888);
        Socket socket = server.accept();
        System.out.println("客户端建立连接");
        DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        String data;
        data=in.readUTF();
        System.out.println(data);
        in.close();
        socket.close();
        
    }
}

 

客户端:

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class client {
    public static void main(String args[]) throws UnknownHostException, IOException {
        System.out.println("客户端启动");
        Socket client=new Socket("localhost",8888);
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
        out.writeUTF("我爱北京天安门");
        out.close();
        client.close();
    }
}

服务端运行结果:

客户端运行结果:

加入多线程实现多台计算机通信:

服务端:

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


class clientThread implements Runnable{
    Socket socket;
    DataInputStream in;
    DataOutputStream out;
    String data;
    String uname=null;
    String upasw=null;
    public clientThread(Socket socket) throws IOException {
        this.socket=socket;
        in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
    }
    @Override
    public void run() {
        // TODO 自动生成的方法存根    
        try {
            System.out.println("iiiiieeeeeee");
            data=in.readUTF();
            System.out.println(data);
            String[] msg=data.split("&");
            for(String info:msg) {
                String[] userinfo=info.split("=");
                if(userinfo[0].equals("用户名")) {
                    System.out.println("用户名:"+userinfo[1]);
                    uname=userinfo[1];
                }
                else if(userinfo[0].equals("密码")) {
                    System.out.println("密码:"+userinfo[1]);
                    upasw=userinfo[1];
                }
//                System.out.println(uname+"--->"+upasw);
            }
            if(uname.equals("ZDL")&&upasw.equals("7820170")) {
                out.writeUTF("登录成功,欢迎回来");
                out.flush();
            }
            else {
                out.writeUTF("登录失败");
                out.flush();
            }
//            in.close();
//            out.close();
//            socket.close();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        System.out.println(data);
        
        
    }
    
}
public class Loginserver {
    public static void main(String args[]) throws IOException {
        ServerSocket server = new ServerSocket(8888);
        Socket socket;
        boolean isrunning=true;
        while(isrunning) {
            socket = server.accept();
            System.out.println("一个客户端建立连接");
            new Thread(new clientThread(socket)).start();
        }
        server.close();
    }
}
View Code

客户端:

package tcp;

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class Loginclient {
    public static void main(String args[]) throws UnknownHostException, IOException {
        System.out.println("客户端启动");
        String uname;
        String upasw;
        Socket client=new Socket("localhost",8888);
//        DataInputStream in = new DataInputStream(new BufferedInputStream(System.in));
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("请输入用户名:");
        uname=in.readLine();
//        System.out.println("1");
        System.out.print("请输入用户密码:");
        upasw=in.readLine();
//        System.out.println("1");
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
        out.writeUTF("用户名="+uname+"&密码="+upasw);
//        System.out.println("1");
        out.flush();
        DataInputStream input = new DataInputStream(new BufferedInputStream(client.getInputStream()));
        String response=input.readUTF();
        System.out.println(response);
        
        out.close();
        client.close();
    }
}
View Code

 

posted on 2019-07-22 13:46  ggsdduzdl  阅读(138)  评论(0编辑  收藏  举报

导航