Java网络编程

预备知识

  • 要学习网络编程首先要了解一些计算机网络的知识。
    • 计算机网络三大要素:通信网络+服务器+客户端
    • 服务器一般使用Linux、Unix或Windows Server等操作系统
    • 不同于之前的非网络程序,网络编程既要求编写客户端应用程序有要求编写服务器端应用程序
    • 遵循TCP/IP协议
      • 应用层
      • 传输层
      • 网络层
      • 链路层
    • 比起UDP只发送不管对方收到没,TCP事先建立连接双向数据传输更可靠
    • 网络上两台计算机之间的通信,本质上是两个网络应用程序之间的通信
    • 统一资源定位符URL语法 protocol://[:port]path[?query]

Java API 提供的因特网地址类java.net.InetAddress

  • 使用方法
import java.io.IOException;
import java.net.*;

public class JInetAddress {

	public static void main(String[] args)  {
		try {
			InetAddress local = InetAddress.getLocalHost(); //获取本机的因特网地址对象
			System.out.println("通过getLoaclHost获得本机因特网网址对象:"+local);
			System.out.println("获取主机名:"+local.getHostName());
			System.out.println("获取主机IP地址:"+local.getHostAddress());
			System.out.println(local.isReachable(1));
			
			String cauWeb = "www.cau.edu.cn";  // 中国农业大学网站的主机名
            InetAddress cau = InetAddress.getByName(cauWeb);  // 根据主机名创建对象
			System.out.println("通过主机名得本机因特网网址对象:"+cau);
			System.out.println("获取主机名:"+cau.getHostName());
			System.out.println("获取主机IP地址:"+cau.getHostAddress());
			
		}
		catch (UnknownHostException e){
			e.printStackTrace();
		}
		catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}
}
  • 实例化一个地址对象–通过静态方法 获取本机的因特网地址对象
InetAddress local = InetAddress.getLocalHost(); 
  • 实例化一个地址对象–通过静态方法 根据主机名创建对象
InetAddress cau = InetAddress.getByName("www.cau.edu.cn"); 
  • 调用非静态方法查看主机名
System.out.println("获取主机名:"+local.getHostName());
  • 调用非静态方法查看IP地址
System.out.println("获取主机IP地址:"+local.getHostAddress());
  • 调用非静态方法查看是否连通
System.out.println(local.isReachable(1));
  • 注意InetAddress可能会抛出的IOException是勾选异常,必须处理

java.net.URL 访问网络资源

import java.net.*;
import java.io.*;
public class JWebPageTest {

	public static void main(String[] args) {
        try {  // 处理可能出现的勾选异常IOException
        	String url_str = "http://www.cau.edu.cn/index.html";
        	//String url_str = "https://www.oracle.com/technetwork/java/index.html";
            URL url = new URL(url_str);
            System.out.println("从网页读取信息: " +url);
            InputStreamReader in = new InputStreamReader(url.openStream(),"UTF-8");
      
           
            char cbuf[] = new char[3000]; //读3000字符
            int len = in.read(cbuf);
            for(int n=0;n<len;n++) {
            	System.out.print(cbuf[n]);
            }
            
            System.out.println("......\n以上是从网页读出的信息。");
            System.out.println("字符编码是:"+in.getEncoding());
            in.close();
        }
        catch(IOException e) { e.printStackTrace(); }  // 捕捉并处理勾选异常

	}

}

一个网络编程的例子(TCP连接)

功能简介:

  • 客户端:向服务端发送请求,从服务端获取当前时间
  • 服务端:监听端口,如果检测到有来自某客户端的请求,就向该客户端输出当前时间

基本思路

  • 服务端与客户端之间建立TCP连接,使用Socket
  • 利用Java.net.Socket搭建客户端应用程序
  • 利用Java.net.ServerSocket搭建服务服务器应用程序
  • 服务端应用程序应该具有处理客户端请求的算法(方法)
  • 应用层协议规定该系统的端口8989(这个端口是我规定的,你可以在自己的协议中指定端口)
  • 服务器遵守协议,监听端口8989
  • 客户端事先知道服务端的ip地址,并且遵守应用层协议,通过8989端口请求服务端

代码实现

  • 服务端
import java.io.*;
import java.net.*;
import java.time.LocalDateTime;

public class JTimeServerST {
	public static void main(String[] args) {
		// 服务端
		try {
			ServerSocket ss = new ServerSocket(8989);
			System.out.println("启动服务器...本端[ "+ss.getLocalSocketAddress()+" ]...");

			while (true) {
				Socket s = ss.accept(); 
				System.out.println("收到请求...并和远端["+s.getInetAddress()+ "]建立了TCP连接");
				timeService(s);
			}
			
		}
		catch(IOException e) {
			System.out.println("IOException1");
		}
	}
	
	public static void timeService(Socket s) {
		System.out.println("timeService()执行中...");
		InputStreamReader in = null;
		OutputStreamWriter out = null;
		
		try {
			// 接受服务请求
			
			in = new InputStreamReader(s.getInputStream());
			char[] buf = new char[7];
			in.read(buf,0,buf.length);
			String request = new String(buf);
			System.out.println("客户端的服务请求是" + request);
			// 发送服务响应
			out = new OutputStreamWriter(s.getOutputStream());
			LocalDateTime t = LocalDateTime.now();
			System.out.println(t);
			String response = String.format("Hello,%s! %s", request, t);
			out.write(response,0,response.length());
			out.flush();
		}
		catch(IOException e) {
			System.out.println("IOException2");
		}
		finally {
			try {
				if(in != null) in.close();
				if(out != null) out.close();
				if(s != null) s.close();
			}
			catch(IOException e) {
				System.out.println("IOException3");
			}
		}
	}
}
  • 客户端
import java.net.*;
import java.io.*;

public class JTimeClient {
	public static void main(String[] args) {
		//客户端
		Socket s = null;
		InputStreamReader in = null;
		OutputStreamWriter out = null;
		
		try {
			s = new Socket("192.168.136.129",8989);
			System.out.println("本端 ["+s.getLocalSocketAddress()+"] connected......");
			System.out.println("远端 ["+s.getRemoteSocketAddress()+"] connected......");
			
			// 发送服务请求
			out = new OutputStreamWriter(s.getOutputStream());
			int id = (int)(Math.random()*10);
			String request = "Clinet" + id;
			out.write(request, 0, request.length());
			out.flush();
			System.out.println("发送的请求是:"+request);
			
			//接受服务响应
			in = new InputStreamReader(s.getInputStream());
			char[] buf = new char[100];
			in.read(buf, 0, buf.length);
			String response = new String(buf);
			System.out.println("接受的服务相应是:"+response);
			
		}
		catch (IOException e) {
			System.out.println("IOException");
		}
		
		finally {
			try {
				if(in != null)
					in.close();
				if(out != null)
					out.close();
				if(s != null)
					s.close();
				System.out.println("客户端程序退出");
			}
			catch(IOException e) {
				System.out.println("IOException");
			}
		}
	}

}

运行

  1. 先启动服务器
    在这里插入图片描述
  • 注:此时没有客户端没有客户端接入
  1. 运行客户端
    在这里插入图片描述

  2. 此时的服务端
    在这里插入图片描述

服务端部分代码解析

  • 启动服务器 创建一个套接字,监听8989端口
ServerSocket ss = new ServerSocket(8989);
  • 在监听端口时发现有TCP连接,确认连接,返回套接字
Socket s = ss.accept();
  • 从套接字Socket中获取输入流对象并进行包装,使之成为更强大的InputStreamReader对象,以便服务端读取来自客户端的信息,即接收来自客户端的服务请求
in = new InputStreamReader(s.getInputStream());
  • 从套接字Socket中获取输入流对象并进行包装,是之成为更强大的OutputStreamWriter对象,以便服务器输出信息到客户端,即向客户端发送服务响应
out = new OutputStreamWriter(s.getOutputStream());

客户端部分代码解析

  • 指定主机IP、端口建立TCP连接
s = new Socket("192.168.136.129",8989);
  • 从套接字Socket中获取到输出流对象并进行包装,使之成为更加强大的OutputStreamWriter对象,以便从客户端输出信息到服务器,即向服务器发送请求
out = new OutputStreamWriter(s.getOutputStream());
  • 从套接字Socket中获取输入流对象并进行包装,使之成为成为更强大的InputStreamReader对象,以便客户端读取来自服务器信息,即接收服务响应
in = new InputStreamReader(s.getInputStream());

另一个网络编程的例子(基于UDP协议)

说明

  • 基于UDP协议的通信是单向连接,发送方只管发送,接受方只管接受,连接不是同时维持的
  • JavaAPI提供java.net.DatagramSocket类包装数据
  • JavaAPI提供数据报套接字类java.net.DatagramSocket类来发送接受数据(DatagramSocket的对象)

发送方

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

public class JUDPSender {
    public static void main(String[] args) {
        try {  
            System.out.print("Send data to...... ");
            // 发送前的准备工作:准备好接收方网址、端口和需发送的数据
            InetAddress udpReceiver = InetAddress.getByName("localhost");
            int port = 9000;
            String msg = "Hello, World!";  
            byte buf[] = msg.getBytes();    //字符流转字节流
            DatagramPacket pack = new DatagramPacket(buf, buf.length, udpReceiver, port);
            DatagramSocket ds = new DatagramSocket();
            ds.send(pack);
            ds.close();
            System.out.println("Done");
        } catch(IOException e) { System.out.println( e.getMessage() ); }
}  }

接收方

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

public class JUDPReceiver {              
    public static void main(String[] args) {  
    try {  
            System.out.println("Receive data ......\n");
            byte buf[] = new byte[128];
            DatagramPacket pack = new DatagramPacket(buf, buf.length);
            DatagramSocket ds = new DatagramSocket(9000);
            ds.receive(pack);
            
            // 分析接收到的数据报包裹,例如发送方的网址、端口和数据等
            InetAddress udpSender = pack.getAddress();
            int port = pack.getPort();
            
            String msg = new String(pack.getData(), 0, pack.getLength());
            System.out.println("Receive data from " +udpSender +":" +port);
            System.out.println("所接收到的数据:" +msg);
    }  
    catch(IOException e) { System.out.println(e.getMessage()); }
}  }

运行

  • 发送方
    在这里插入图片描述
  • 接受方
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值