第二十一章网络通信总结

文章目录

网络程序设计基础

网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素封

装成不同的类,用户只要创建这些类的对象,使用相应的方法,即使不具备有关的网络支持,也可

以编写出高质量的网络通信程序。

局域网与互联网

为了实现两台计算机的通信,必须用一个网络线路连接两台算计

服务器是指提供信息的计算机程序

客户机是指请求信息的计算机或程序

网络用于连接服务器与客户机,实现两者的相互通信。但是,有时在某个网络中很难将服务器与客户机区分开。局域网 (LAN) 是一群通过一定形式连接起来的计算机,它可以由两台计算机组成,也可以由同一区域内地上千台计算机组成。将 LAN 延伸到更大的范围,这样的网络成为广域网(WAN)。互联网是由无数的 LAN 和 WAN 组成的。

网络协议

网络协议规定了计算机之间连接的物理、机械(网络与网卡的连接规定)、电气(有效的电平范围)等特征,计算机之间的相互寻址规则,数据发送冲突的解决方式,长数据如何分段传送与接收等内容。

IP协议

IP 是 Internet Protocol 的简称,是一种网络协议。Internet 网络采用的协议是 TCP/IP协议。TCP/IP 模式是一种层次结构,共分为 4 层,分别为应用层、传输层、互联网层和网络层。各层实现特定的功能,提供特定服务和访问接口,并具有相对的独立性。

TCP/IP 协议

在TCP/IP 协议栈中有两个高级协议 :

传输控制协议(TCP)

用户数据报协议(UDP)

端口域套接字

一般而言,一台计算机只有单一的连接到网络的物理连接,所以的数据读通过此连接对内、

对外送达特定的计算机,这就是端口。网络程序设计的端口(port)并非真实的物理存在,而是一个假想的连接装置。

网络程序中的套接字(Socket)用于将应用程序 与端口连接起来。套接字是一个假想的连接装置,就像插座一样可以连接电器与电线。

TCP 程序

TCP 网络程序设计是利用 Socket 类编写通信程序。利用 TCP 协议进行通信的两个应用程序是有主次之分的,一个称为服务器程序,另一个称为客户机程序,两者的功能和编写方法大不一样。

InterAddress 类

java.net 包中的 InterAddress 类是与 IP 地址相关的类,利用该类可以获取 IP 地址、主机地址等信息。

示例:

java 复制代码
import java.net.*;
 
public class Demo21_1 {
 
	public static void main(String[] args) {
		InetAddress ip;//创建InetAddress对象
	
			try {//捕捉异常
				ip=InetAddress.getLocalHost();//实例化对象
				String ming=ip.getHostName();//获取本机名
				String dizi=ip.getHostAddress();//获取本机地址
				System.out.println("本机名:"+ming);//输出本机名
				System.out.println("本机IP地址:"+dizi);//将本机IP地址输出
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();//输出异常
			}
		
 
	}
 
}

ServerSocket 类

java.net 包中的 ServerSocket 类用于表示服务器套接字,其主要功能是等待来自网络上的

"请求",它可以通过指定的端口来等待连接的套接字。服务器套接字一次可以与一个套接字。如果

多台客户机同时提供出连接请求,服务器套接字会将请求连接的客户机存入列队中,然后从中取出

一个套接字,与服务器新建的套接字连接起来。若请求连接大于最大容纳数,则多出的连接请求被

拒绝。队列的默认大小是 50。

ServerSocket 类的构造方法通常会抛出 IOException 异常,具体有以下几种形式:

ServerSocket(): 创建非绑定服务器套接字。

ServerSocket(int port): 创建绑定到特定端口的服务器套接字。

ServerSocket(int port,int backlog): 利用指定的 backlog 创建服务器套接字,并将其绑定到指定的本地端口号上。

ServerSocket(int port,int backlog,InetAddress bindAddress): 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。这种情况适用于计算机上有多块网卡和多个IP 地址的情况,用户可以明确规定 ServerSocket 在哪块网卡或哪个 IP 地址上等待客户的连接请求。

详见Java1.8API文档

示例:创建 TCP/IP 协议服务器,本实例是一个 TCP服务器端程序。

java 复制代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
 
public class Demo21_2 {
	private ServerSocket s;//服务器套接字
	private Socket sk;//客户端套接字
	void start() {//启动服务器
		try {
			s=new ServerSocket(8998);//服务器启用8998端口
			System.out.println("服务器套接字已经创建成功");
			while(true) {
				System.out.println("等待客户机的接入");
				sk=s.accept();//监听客户机的连接
				BufferedReader r=new BufferedReader(new InputStreamReader(sk.getInputStream()));
				while(true) {//循环接收信息
					String m=r.readLine();//读取一行文本
					if("退出".equals(m)) {//如果客户机发来的内容为退出
						System.out.println("客户机退出");
						break;//停止接收信息
					}
					System.out.println("客户机"+m);
					
				}
				r.close();//关闭流
				sk.close();//关闭套接字
			}
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		Demo21_2 tcp=new Demo21_2();
		tcp.start();//启动服务器
 
	}
 
}

服务器端

java 复制代码
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
 
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
public class Demo21_2_2 extends JFrame{
	 private PrintWriter w;//字符输出流
	  Socket s;//客户端套接字
	 private JTextArea area=new JTextArea();//文本域
	 private JTextField text=new JTextField();//文本框
	 public Demo21_2_2() {
		 setTitle("向服务器送数据");
		 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 Container c=getContentPane();//主容器
		 JScrollPane scrollPane=new JScrollPane(area);//滚动面板
		 getContentPane().add(scrollPane,BorderLayout.CENTER);
		 c.add(text,"South");//将文本框放到窗体下部
		 text.addActionListener(new ActionListener() {//文本框触发回车事件
			 public void actionPerformed(ActionEvent e) {
				 w.println(text.getText().trim());//将文本框的信息写入流
				 area.append(text.getText()+"\n");//将文本框的信息显示在文本域中
				 text.setText("");//将文本框清空
			 }
		 });
	 }
	 public void c() {//连接服务器方法
		 area.append("尝试连接\n");//文本域中提示信息
		 try {
			 s=new Socket("127.0.0.1",8998);//连接本地计算机的端口8998
			 w=new PrintWriter(s.getOutputStream(),true);
			 area.append("完成连接\n");
		 }catch(IOException e) {
			 e.printStackTrace();
		 }
	 }
	 
	public static void main(String[] args) {
		Demo21_2_2 c=new Demo21_2_2();
		c.setSize(200, 200);//窗体大小
		c.setVisible(true);//是否显示
		c.c();//连接服务器
 
	}
 
}

UDP 程序

用户数据报协议 (UDP) 是网络信息传输的另一种形式。基于 UDP 的通信和基于 TCP 的通信基于 UDP的信息传递更快,但不提供可靠性保证。使用 UDP 传递数据时,用户无法知道数据能否正确地到达主机,也不能确定到达目的地的顺序是否和发送相同。虽然 UDP 是一种不可靠的员议,但如果需要较快地传输信息,并能容忍小的错误,可以考虑使用 UDP。

基于 UDP 通信的基本模式如下:

将数据打包 (称为数据包),然后将数据包发往目的地。

接收别人发来的数据包,然后查看数据包。

发送数据包的步骤如下:

使用 DatagramSocket() 创建一个数据包套接字。

使用 DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)创建要发送的

数据包。

使用 DatagramSocket 类的 send() 方法发送数据包。

接收数据包的步骤如下:

使用 DatagramSocket(int port) 创建数据包套接字,绑定到指定的端口。

使用 DatagramPacket(byte[]buf,int length) 创建字节数组来接收数据包。

使用 DatagramPacket 类的 receive() 方法接收UDP包。

DatagramPacket 类

java.net 包的 DatagramPacket 类用来表示数据包。DatagramPacket 类的构造方法如下:

第一种构造方法在创建 DatagramPacket 对象时,指定了数据包的内存空间和大小。第二种构造方法不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和口、在发送数据时,必须指定接收方的 Socket 地址和端口号,因此使用第二种构造方法可创建发送数据的 DamgramPacket 对象。

DatagramSocket 类

javanet 包中的 DatagramSocket 类用于表示发送和接收数据包的套接字。该类的构造方法如下:

第一种构造方法创建 DatagramSocket 对象,构造数据报套接字,并将其绑定到本地主机任何可用的端口上。第二种构造方法创建 DatagramSocket 对象,创建数据报套字,并将其绑定到本地主机的指定端口上。第三种构造方法创建 DatagramSocket 对象,创建数据报套接字,并将其绑定到指定的端口和指定的本地地址上。第三种构造函数适用于有多块网卡和多个 IP 地址的情况。

示例:创建 UDP 协议广播电台程序,广播主机程序不断地向外播出信息。

发送数据部分:

java 复制代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
 
 
 
public class Demo21_3 extends Thread{
	String weather="节目预报:八点有大型晚会,请收听";
	int port=9898;
	InetAddress  iaddress=null;
	MulticastSocket socket=null;
	
	Demo21_3(){
		try {
			iaddress=InetAddress.getByName("224.225.10.1");
			socket=new MulticastSocket(port);
			socket.setTimeToLive(1);
			socket.joinGroup(iaddress);
			}catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	public void run() {
		while(true) {
		DatagramPacket packet=null;
		byte date[]=weather.getBytes();
		packet=new DatagramPacket(date,date.length,iaddress,port);
		System.out.println(weather);
		
			try {
				socket.send(packet);
				sleep(3000);
			}  catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
			
	
	}
	public static void main(String[] args) {
		Demo21_3 w=new Demo21_3();
		w.start();
 
	}
 
}

接收数据部分:

java 复制代码
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
 
public class Demo21_3_2  extends JFrame implements Runnable,ActionListener{
	int port=9898;
	InetAddress  group=null;
	MulticastSocket socket=null;
	JButton inceBth=new JButton("开始接收");
	JButton stopBth=new JButton("停止接收");
	JTextArea inceAr=new JTextArea(10,10);
	JTextArea inced=new JTextArea(10,10);
	Thread thread;
	boolean stop=false;
	 public Demo21_3_2() {
		 setTitle("广播数据");
		 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		 thread=new Thread(this);
		 inceBth.addActionListener(this);
		 stopBth.addActionListener(this);
		 inceAr.setForeground(Color.blue);
		 JPanel north=new JPanel();
		 north.add(inceBth);
		 north.add(stopBth);
		 add(north,BorderLayout.NORTH);
		 JPanel center=new JPanel();
		 center.setLayout(new GridLayout(1,2));
		 center.add(inceAr);
		 center.add(inced);
		 add(center,BorderLayout.CENTER);
		validate();
		try {
			group=InetAddress.getByName("224.225.10.1");
			socket=new MulticastSocket(port);
			socket.joinGroup(group);
		}catch(IOException e) {
			e.printStackTrace();
		}
		setBounds(100,50,360,380);
		setVisible(true);
		
	 }
	 public void  run() {
		 while(!stop) {
			 byte date[] = new byte[1024];
			 DatagramPacket packet=null;
			 packet=new DatagramPacket(date,date.length,group,port);
			 try {
				 socket.receive(packet);
				 String message=new String(packet.getData(),0,packet.getLength());
				 inceAr.setText("正在接收内容:\n"+message);
				 inced.append(message+"\n");
			 }catch(IOException e) {
				 e.printStackTrace();
			 }
		 }
	 }
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==inceBth) {
			inceBth.setBackground(Color.red);
			stopBth.setBackground(Color.yellow);
			if(!(thread.isAlive())) {
				thread=new Thread(this);
				
			}
			thread.start();
			stop=false;
			
		}
		if(e.getSource()==stopBth) {
			inceBth.setBackground(Color.yellow);
			stopBth.setBackground(Color.red);
			stop=true;
		}
	}
	public static void main(String[]args) {
		Demo21_3_2 rec=new Demo21_3_2();
		rec.setSize(460, 200);
	}
}
相关推荐
hrrrrb1 分钟前
【Spring Security】Spring Security 密码编辑器
java·hive·spring
豐儀麟阁贵4 分钟前
2.3变量与常量
java·开发语言
兮动人1 小时前
Eureka注册中心通用写法和配置
java·云原生·eureka
爱编程的小白L3 小时前
基于springboot志愿服务管理系统设计与实现(附源码)
java·spring boot·后端
聪明的笨猪猪5 小时前
Java Redis “持久化”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
聪明的笨猪猪6 小时前
Java Redis “核心基础”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
奋斗的小monkey8 小时前
Spring Boot 3.x核心特性与性能优化实战
java·spring boot·微服务·性能优化·响应式编程
程序猿DD8 小时前
将 GPU 级性能带到企业级 Java:CUDA 集成实用指南
java·架构
一成码农9 小时前
JavaSE面向对象(上)
java