java第二十一章网络通信
Java网络通信
由于数据链路层编程和通信与设备紧密关联,网络层编程和操作系统紧密关联。Java网络编程从传输层开始,并根据编程使用协议的层次分为高层次网络编程(基于应用层)和低层次网络编程(基于传输层)。
基于URL使用高层次网络编程,基于传输层使用低层次网络编程。
网络通信协议
物理层(Physical Layer):局部局域网上传送数据框(frame),它负责管理电脑通信设备和网络媒体之间的互通,通过物理电气接口实现互联设备间的比特形式的信息传输
数据链路层(Data Link Layer):负责网络寻址、错误侦测和改错,是网络相邻节点设备间二进制信息传输的数据通道,负责数据通道的建立和拆除。
网络层(Network Layer):决定数据的路径选择和转寄,将网络表头(NH)加至数据包,以形成分组,解决跨越多个链路的甚至不同网络设备之间的通信问题,是一种端到端的通信
传输层(Transport Layer):把传输表头(TH)加至数据以形成数据包,解决处于不同网络设备间的通信传输、通信管理,对上层需要通信的数据信息分解为标准的数据单元,这些数据单元到达终端后能对这些数据单元进行重新排序和整合。
会话层(Session Layer):负责在数据传输中设置和维护电脑网络中两台电脑之间的通信连接,为用户交互信息而按特点规律建立的连接,提供会话地址和会话管理服务
表示层(Presentation Layer):将会话层得到的数据转化为应用层可以理解的表达形式,或则将数应用层数据转化为会话层可以传输的形式
应用层(Application Layer):提供为应用软件而设的界面,以设置与另一应用软件之间的通信
TCP与UDP
TCP与UDP都是传输层的协议
TCP (Transmission Control Protocol)——传输控制协议
UDP (User Data Protocol)——用户数据报协议
?
TCP:协议的连接过程为:设主机A与主机B建立连接,主机A先发送一个特殊的“连接请求消息段”给B,B接收到消息后就分配相应的资源(接收缓存和发送缓存)给这个TCP连接,然后给A发送一个“允许连接消息段”,A收到这个消息段后也分配相应资源,然后给B发送“确认消息段”,这是就建立起了TCP连接,可以相互传输数据。A与B之间的连接要连续交换3次消息(三次握手法),保证了连接传输的可靠性。
服务端
package d21z;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
/**
* Socket客户端
**/
public class SocketClient {
public static void main(String[] args) {
Socket s = null;
try {
// 与ip为127.0.0.1、端口为12345的服务端建立连接
s = new Socket("127.0.0.1", 12345);
// 创建输入流接收服务端发送的消息(字节流)
InputStream is = s.getInputStream();
// 将服务端返回的字节流转化为字符流
InputStreamReader isr = new InputStreamReader(is);
// 创建字符流读取缓冲区,方便每行读取
BufferedReader br = new BufferedReader(isr);
// 创建输出流返回消息
OutputStream os = s.getOutputStream();
// 创建输出流缓冲
PrintWriter pw = new PrintWriter(os);
// 创建发送消息的线程
Runnable rOut = () -> {
boolean flag = true;
while (flag) {
try {
// 接收控制台输入
Scanner scan = new Scanner(System.in);
String msg = scan.nextLine();
// 将输入写入缓冲
pw.println(msg);
// 将缓冲内的数据推送至服务端并清空缓冲区
pw.flush();
} catch (Exception e) {
flag = false;
e.printStackTrace();
}
}
};
// 创建接收消息的线程
Runnable rIn = () -> {
boolean flag = true;
while (flag) {
try {
// 逐行读取服务端返回的消息并打印
String str = br.readLine();
System.out.println("服务端的消息:" + str);
} catch (IOException e) {
flag = false;
e.printStackTrace();
}
}
};
// 启动两个线程
Thread tOut = new Thread(rOut);
Thread tIn = new Thread(rIn);
tOut.start();
tIn.start();
}catch (IOException e) {
try {
// 释放资源
s.close();
} catch (Exception exception) {
exception.printStackTrace();
}
e.printStackTrace();
}
}
}
客户端
package d21z;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* Socket服务端
**/
public class SocketServer {
public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
try {
// 创建监听端口为12345的Socket服务端
ss = new ServerSocket(12345);
System.out.println("服务端Socket服务已建立,等待客户端连接...");
// 通过ss.accept()开始持续监听12345端口,当有连接时获取收到的包装成Socket的客户端对象
s = ss.accept();
// 获取客户端的IP地址和端口号
String ip = s.getInetAddress().getHostAddress();
int port = s.getPort();
System.out.println("服务端与 " + ip + ":" + port + " 已建立连接");
// 创建输入流接收客户端发送的消息(字节流)
InputStream is = s.getInputStream();
// 将客户端发送的字节流转化为字符流
InputStreamReader isr = new InputStreamReader(is);
// 创建字符流读取缓冲区,方便每行读取
BufferedReader br = new BufferedReader(isr);
// 创建输出流返回消息
OutputStream os = s.getOutputStream();
// 创建输出流缓冲
PrintWriter pw = new PrintWriter(os);
// 创建接受信息的线程
Runnable rIn = () -> {
boolean flag = true;
while (flag) {
try {
// 逐行读取客户端发送的消息并打印
String str = br.readLine();
System.out.println("客户端的消息:" + str);
} catch (IOException e) {
flag = false;
e.printStackTrace();
}
}
};
// 创建发送消息的线程
Runnable rOut = () -> {
boolean flag = true;
while (flag) {
try {
// 接收控制台输入
Scanner scan = new Scanner(System.in);
String msg = scan.nextLine();
// 将输入写入缓冲
pw.println(msg);
// 将缓冲内的数据推送至客户端并清空缓冲区
pw.flush();
} catch (Exception e) {
flag = false;
e.printStackTrace();
}
}
};
// 开启两个线程
Thread tIn = new Thread(rIn);
Thread tOut = new Thread(rOut);
tIn.start();
tOut.start();
} catch (IOException e) {
try {
// 释放资源
ss.close();
s.close();
} catch (Exception exception) {
exception.printStackTrace();
}
e.printStackTrace();
}
}
}
结果:
?
UDP:完全依赖IP协议,是无连接的协议,每个数据报都是独立的信息,可能以任何可能的路径传向目的地,可以同时向多个对象进行传输,但传输的可靠性不能被保证。
服务端?
package d21z;
import java.io.IOException;
import java.net.*;
public class Notification extends Thread{
String weather ="节目预报:八点有大型晚会,请收听!";
int port=9898;
InetAddress iaddress=null;
MulticastSocket socket=null;
Notification(){
try {
iaddress=InetAddress.getByName("224.255.10.0");
socket=new MulticastSocket(port);
socket.setTimeToLive(1);
socket.joinGroup(iaddress);
}catch(IOException e) {
e.printStackTrace();
}
}
public void run() {
while(true) {
DatagramPacket packet = null;
byte data[] = weather.getBytes();
packet = new DatagramPacket(data,data.length,iaddress,port);
System.out.println(weather);
try {
socket.send(packet);
sleep(3000);
}catch(IOException e) {
e.printStackTrace();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Notification w = new Notification();
w.start();
}
}
?客户端
package d21z;
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 Reveive extends JFrame implements Runnable, ActionListener {
int port ;//端口
InetAddress group =null;//广播组地址
MulticastSocket socket = null;//多点广播套接字对象
JButton inceBtn = new JButton("开始接收");
JButton stopBtn = new JButton("停止接收");
JTextArea inceAr = new JTextArea(10,10);//显示接收广播的文本域
JTextArea inced = new JTextArea(10,10);
Thread thread ;
boolean stop = false;//定制接受信息状态
public Reveive () {
setTitle("广播数据包");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
thread = new Thread(this);
inceBtn.addActionListener(this);//绑定按钮ince的单击事件
stopBtn.addActionListener(this);//绑定按钮stop的单击事件
inceAr.setForeground(Color.blue);//指定文本域中文字的颜色
JPanel north = new JPanel();
north.add(inceBtn);//将按钮添加到面板north上
north.add(stopBtn);
add(north,BorderLayout.NORTH);//将north放置在窗体的上部
JPanel center = new JPanel();//创建面板对象center
center.setLayout(new GridLayout(1,2));//设置面板布局
center.add(inceAr);//将文本域添加到面板上
center.add(inced);
add(center,BorderLayout.CENTER);//设置面板的布局
validate();//刷新
port =9898;//设置端口号
try {
group = InetAddress.getByName("224.255.10.0");//指定接收地址
socket = new MulticastSocket(port);//绑定多点广播套接字
socket.joinGroup(group);//加入广播组
}catch(IOException e){
e.printStackTrace();//输出异常信息
}
setBounds(100,50,360,380);//设置布局
setVisible(true);//将窗体设置为显示状态
}
public void run() {//run方法
while (!stop) {
byte data[] = new byte[1024];//创建缓存字节数组
DatagramPacket packet = null;
packet = new DatagramPacket(data,data.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) {//单机按钮ince出发时间
if(e.getSource()==inceBtn) {
inceBtn.setBackground(Color.red);//设置按钮颜色
stopBtn.setBackground(Color.yellow);
if(!(thread.isAlive())) {//如线程不处于“新建状态”
thread = new Thread(this);//实例化Thread对象
}
thread.start();//启动线程
stop = false;//开始接受信息
}
if(e.getSource()== stopBtn) {//单机按钮stop出发时间
inceBtn.setBackground(Color.yellow);//设置按钮亚瑟
stopBtn.setBackground(Color.red);
stop = true;//停止接收信息
}
}
public static void main(String[]args) {
Reveive rec = new Reveive();
rec.setSize(460,200);
}
}
?结果:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!