Java学习笔记08(网络编程)

网络编程

InetAddress类

Java中提供一个与 IP 地址相关的 InetADddress 类 ,该类用于封装一个IP地址,提供一些与 IP 地址相关 的 方法;

方法举例;

InetAddress getByName(String host)   //获取给的主机名的 IP 地址, host参数表示知道主机。
InetAddress getLocalHost()			//获取本地本机地址
String getHostName()			   // 获取本地IP地址的主机名;
boolean isReachable(int timeout)	// 判断在限定时间内指定的IP地址是否可以访问;
String getHostAddress()				//获取字符串格式的原始IP地址

代码案例:

 public static void main(String[] args) throws Exception {
        InetAddress localAddress = InetAddress.getLocalHost(); //获取本地主机 InetAddress对象;
        InetAddress remoteAddress = InetAddress.getByName("www.baidu.com"); //获取 主机名为 “www.baidu.com"的InetAddress对象;
        System.out.println("本机的IP地址:" + localAddress.getHostAddress());
        System.out.println("baidu的IP地址:" + remoteAddress.getHostAddress());
        System.out.println("三秒内是否可以访问:"+ remoteAddress.isReachable(3000));
        System.out.println("baidu的主机名:" + remoteAddress.getHostName());
    }
// InetAddress 对象 是一个  主机名+IP地址 的组合
//通过 getByName(String host) 获得 InetAddress对象;

UDP通信

UDP是一种面向无连接的通信;Java中提供两个类来实现 UDP通信;
DatagramPacket类: 该类 用于 封装UDP通信中的 数据信息;
DatagramSocket类: 该类用于 发送和接收 数据;

DatagramPacket类

用于封装UDP通信中的数据;

构造方法:

该类的接收端的构造方法 只需要接收一个字节数组来存放接收到的数据;而发送端必须指出 IP地址 和 端口号;
接收端的构造方法;

1DatagramPacket(byte[] buf , int length); // (1) 指定封装数据的字节数组 和 数据的大小,没有指定IP和端口号;2DatagramPacket(byte[] buf , int offset , int length) // 和第一个类似,只是从 offset 位置开始发送数据

发送方的构造方法;

(1)  DatagramPaket(byte[] buf,int length, InetAddress addr, int port)   //指明IP地址和端口号
(2)  DatagramPaket(byte[] buf,int setoff ,int length, InetAddress addr, int port)   //从 offset 位置开始发送数据

DatagramPacket 常用方法:

InetAddress getAddress();   //用于返回发送端或者接收端的IP地址, 如果是发送端的DatagramPacket 对象,则返回接收端的IP地址,反之亦然
int getPort();			   // 用于返回发送端或者接收端的端口号,如果是发送端的DatagramPacket 对象,则返回接收端的端口号,反之亦然
byte[] getData();           //  用于返回将要接收或者发送的数据,如果是发送端的DatagramPacket 对象,就返回将要发送的数据,反之亦然
int getLength();		   //  同于返回接收或者将要发送数据的长度,如果是发送端的DatagramPacket 对象,就返回将要发送的数据长度,反之亦然;

DatagramSocket

用于创建发送端和接受端的对象;

构造方法:

1DatagramSocket(); //创建发送端的 DatagramSocket对象。没有指定端口号,系统自动分配一个网络程序中没有使用的端口号2DatagramSocket(int port); //可以创建接收端或发送端的 DatagramSocket 对象,创建接收端时,必须指定端口号;3DatagramSocket(int port,InetAddress addr); //指定出了IP地址,适用于计算机中有很多网卡的情况;

DatagramSocket 常用方法;

void receive(DatagramPacket p); //该方法用于接收 DatagramPacket数据报,没有收到之前处于阻塞状态,若发送的消息过长,会被截取;
void send(DatagramPacket p);   //用于发送 DatagramPacket 数据报,数据报中要包含 发送的数据,数据长度,远程主机IP地址,端口号
void close();   				// 关闭当前 Socket,释放资源

两个类使用举例:

//接收端程序
public class UDPReceiver {
    public static void main(String[] args) throws Exception {
        DatagramSocket server = new DatagramSocket(8900);//创建接口端对象,指定端口号8900;
        byte[] buf = new byte[1024];                            //定义字节数组,用于接收数据。
        DatagramPacket packet = new DatagramPacket(buf, buf.length);//定义一个DatagramPacket对象,用于封装接收的数据;
        System.out.println("等待接收数据");
        while (true) {
            server.receive(packet);  //用于接收数据报数据,没有收到之前处于阻塞状态;
            String str = new String(packet.getData(), 0, packet.getLength());//调用 Packet中的 getData方法获取信息,并转化为字符串
            System.out.println(packet.getAddress() + ":" + packet.getPort() + "发送信息" + str);
        }
    }

    //发送端程序
public class UDPSender {
    public static void main(String[] args) throws Exception {
        DatagramSocket client = new DatagramSocket(3000);  //指定发送端的端口号3000;
        String str = "你好, 中国!";   //定义要发送的数组
        //定义 一个DatagramPacket数据包,封装发送端信息以及发送地址
        DatagramPacket packet = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("localhost"), 8900);
        System.out.println("开始发送数据...");
        client.send(packet);            //发送数据
        client.close();                 //释放资源
    }
}

聊天室案例:

//聊天室
public class ChatRoom {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入聊天服务当前的端口号");
        int serverPort = sc.nextInt();
        System.out.println("请输入聊天服务发送信息对象的目标端口号:");
        int targetPort = sc.nextInt();
        System.out.println("聊天系统初始化完成");
        try {
            DatagramSocket socket = new DatagramSocket(serverPort);
            new Thread(new ChatReceiver(socket),"接收服务").start();
            new Thread(new ChatSender(socket, targetPort),"发送服务").start();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public class ChatReceiver implements Runnable{
    //接收方程序;
    private DatagramSocket server ;
    public ChatReceiver(DatagramSocket server){
        this.server = server;
    }
    @Override
    public void run() {
        try {
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer,buffer.length);//封装接收的数据;
            while (true){
                server.receive(packet);
                String str = new String(packet.getData(),0,packet.getLength()); //将接收的 数据转化为字符串类型;
                System.out.println("收到"+ packet.getAddress()+":"+packet.getPort()+"发送的数据\n"+str);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
    
//发送方
public class ChatSender implements Runnable{
    private DatagramSocket client;
    private int targetPort; //指定 发送的 端口号;
    public ChatSender(DatagramSocket client, int targetPort){
        this.client = client;
        this.targetPort = targetPort;
    }
    @Override
    public void run() {
      try {
          //获取输入的信息;
          Scanner sc = new Scanner(System.in);
          while (true){
              String data = sc.nextLine();
              byte[] buffer = data.getBytes();
              DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getByName("localhost"),targetPort);
              client.send(packet);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
    }
}

在控制台运行两次 main方法即可使用;

TCP通信

UDP中只有发送端和接收端,不区分客户端和服务器端,计算机之间可以任意发送数据。而TCP通信是严格区分客户端和服务器端的,通信时必须有客户端先连接服务器端,服务器 不可以主动连接客户端;

JDK中提供两个类用户实现TCP程序; ServerSocket 类,用于表示服务器端。Socket 类,用户表示客户端;

ServerSocket类

该类的实例对象可以实现一个服务的程序;

构造方法:

(0) ServerSocket();				//创建对象时没有指定端口号,因此该对象不监听任何端口,不能直接使用
							  //使用时需要 调用 bind(SocketAddress endpoint) 方法将其绑定到指定的端口号上
(1) ServerSocket(int port);		//可以绑定端口号。若参数值为0,系统分配一个未被其他程序占有的端口号;
(2) ServerSocket(int port, int backlog) ; //增加一个backlog参数。 用于指定在服务器忙时,可以与之保持链接请求的等待客户端数量,默认为50;
(3) ServerSocket(int port, int backlog, InetAddress bindAddr) //指定相关的IP地址,适用于有多个网卡多个IP地址的情况;

常用方法:

Socket accept();		//用于等待客户端的连接,链接之前处于阻塞状态,有连接返回一个 客户端对应的Socket对象;
InetAddress getInetAddress(); //返回一个InetAddress对象,该对象中封装了ServerSocket 绑定的IP地址;
boolean isClosed();			//判断 ServerSocket对象 是否关闭;
void bind(SocketAddress endpoint)  //将 ServerSocket 对象 绑定到 指定的IP地址和端口号上,endpoint封装了 IP地址 和端口号;

Socket类

用于实现TCP客户端程序;

构造方法:

(0) Socket();       // 没有指定IP地址和端口号,只创建了对象,没有链接服务器。 该对象通过 connect(SocketAddress endpoint)方法才能链接服务器
				  //endpoint封装了 IP地址 和端口号;
(1) Socket(String host, int port); // 该对象 连接 指定的 地址和端口上运行的服务器程序, host 表示字符串类型的IP地址;
(2) Socket(InetAddress address, int port); // InetAddress 封装一个IP地址;

常用方法:

int getPort(); //返回 此 Socket 连接的远程服务器端口;
InetAddress getLocalAddress();  //获取 Socket对象绑定的IP地址,返回 IP地址封装的 InetAddress 形式;
void close();				// 关闭Socket连接
InputStream getInputStream()//返回 输入流对象。如果该对象由 服务器端的Socket返回,就用于读取 客户端发送的数据;反之亦然
OutputSream getOutputStream();   //返回 输出流对象。如果该对象由 服务器端的Socket返回,就用于向 客户端发送数据;反之亦然

案例:

//TCP服务器
public class TCPServer {
    public static void main(String[] args) throws  Exception{
        ServerSocket server = new ServerSocket(7700);   //创建端口为7700的TCP服务端 ServerSocket对象;
        while (true){
            Socket client = server.accept();  //调用 accept() 方法 开始接收数据;
            System.out.println("与客户端连接成功,开始进行数据交互");
            OutputStream os = client.getOutputStream(); // 获取客户端的输出流对象;
            os.write(("服务器端向客户端发出响应!").getBytes());  //向客户端 输出数据;
            Thread.sleep(5000);                 //模拟与客户端交互耗时;
            os.close();
            client.close();                         //关闭 流 和 Socket 连接
        }
    }
}

public class TCPClient {
    public static void main(String[] args) throws Exception {
        Socket client = new Socket(InetAddress.getLocalHost(), 7700); //创建 Socket 对象,连接到指定服务器端;
        InputStream is = client.getInputStream();   //获取 服务端返回的 输入流 数据 ;
        byte[] buffer = new byte[1024];
        int len = is.read(buffer);
        while (len != -1) {
            System.out.println(new String(buffer,0,len));
            len = is.read(buffer);
        }
        is.close();
        client.close();
    }
}

多线程的TCP网络程序

//多线程TCP服务器端;
public class ThreadTCPServer {
    public static void main(String[] args) throws Exception{
        ServerSocket server = new ServerSocket(7788);//创建一个绑定的端口号为7788的 TCP服务器端 对象
        //循环等待 等待客户端连接
        while(true){
            Socket client = server.accept();          //等待服务器连接
            //针对每一个客户端请求 创建一个线程进行连接管理;
            Thread thread = new Thread(()->{
                try {
                    int port = client.getPort(); //得到连接的客户端的端口号;
                    System.out.println("与端口号为:"+port + "的客户端成功建立连接!");
                    OutputStream os = client.getOutputStream();
                    os.write(("服务器向客户端发出响应!!").getBytes());
                    Thread.sleep(5000);
                    System.out.println("结束客户端和服务器端的交互");
                    os.close();
                    client.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            });
            thread.start();
        }
    }
}
// 多个 TCPClient 可以 与 TCP服务器端建立连接
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值