Java033-网络编程
本帖最后由 moc 于 2019-8-29 21:02 编辑1、简介
1. 网络编程含义:
用Java语言实现计算机间数据的信息传递和资源共享。
2. 网络编程模型:
① OSI(Open System Interconnection开放系统互连)参考模型(7 层模型)
应用层 》表示层 》会话层 》传输层 》网络层 》数据链路层 》物理层
② TCP/IP参考模型
应用层 》传输层 》网际层 》链路层 》物理层
3. 网络编程三要素:
① IP地址
》点分十进制记法,私有地址不在互联网上使用,用于局域网。
》A类地址: 1.0.0.1—126.255.255.254 --- 保留给政府机构{10.X.X.X是私有地址}
》B类地址:128.0.0.1—191.255.255.254--- 中等规模的公司{172.16.0.0—172.31.255.255是私有地址、169.254.X.X是保留地址}
》C类地址:192.0.0.1—223.255.255.254--- 任何需要的人{192.168.X.X是私有地址}
》D类地址:224.0.0.1—239.255.255.254
》E类地址:240.0.0.1—255.255.255.254
》127.X.X.X为保留地址,用做循环测试用的。
② 端口
同一个主机内不同应用程序的标识,范围:0-65535。其中0-1024不建议使用。
③ 协议
》TCP:建立数据通道,全双工,无边界流,效率低,面向连接,可靠
》UDP:无数据通道,全双工,数据打包,效率高,无连接,不可靠
4. Socket机制
① 通信两端都应该有Socket对象;
② 客户端和服务器通过对 Socket 对象的写入和读取来进行通信;
2、UDP通讯
1. 相关API
InetAddress类: --- 互联网协议 (IP) 地址
public static InetAddress getByName(String host) ----> 在给定主机名的情况下确定主机的 IP 地址; 主机名可以是机器名,也可是其 IP 地址的文本表示形式。
public String getHostName()---------------------------->获取此 IP 地址的主机名。
public String getHostAddress() -------------------------->返回 IP 地址字符串(文本表现形式)。
DatagramSocket类: --- 表示用来发送和接收数据报包(UDP)的套接字
public DatagramSocket()----------------------------------- -->构造数据报套接字并将其绑定到本地主机上任何可用的端口。
public DatagramSocket(int port)----------------------------->创建数据报套接字并将其绑定到本地主机上的指定端口,IP 地址由内核选择。
public DatagramSocket(int port, InetAddress laddr) ------>创建数据报套接字,将其绑定到指定的本地地址。
public void receive(DatagramPacket p)--------------------->从此套接字接收数据报包。
public void send(DatagramPacket p) ------------------------>从此套接字发送数据报包。
DatagramPacket类: --- 表示数据报包,用来实现无连接包投递服务。
public DatagramPacket(byte[] buf, int length)------------>构造 DatagramPacket,用来接收长度为 length 的数据包。
public DatagramPacket(byte[] buf, int length, InetAddress address, int port)-----> 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
public InetAddress getAddress()----------------------------->返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
public byte[] getData() --------------------------------------> 返回将要发送或接收到的数据缓冲区内容。
public int getLength()------------------------------------------>返回将要发送或接收到的数据的长度。
2. UDP协议发送数据
步骤:
① 创建发送端Socket对象;
② 创建数据,并把数据打包;
③ 调用Socket对象的发送方法发送数据包;
④ 释放资源。
public class UdpSendDemo {
public static void main(String[] args) throws IOException {
// 创建发送端Socket对象
DatagramSocket ds = new DatagramSocket();
// 创建数据,并把数据打包
byte[] bys = "UDP,你好!".getBytes();// 创建数据
int length = bys.length;// 长度
InetAddress address = InetAddress.getByName("192.168.12.92");// IP地址对象
int port = 10086; // 端口
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
// 调用Socket对象的发送方法发送数据包
ds.send(dp);
// 释放资源
ds.close();
}
}3. UDP协议接受数据
步骤:
① 创建接收端Socket对象;
② 创建一个数据包(接收容器);
③ 调用Socket对象的接收方法接收数据;
④ 解析数据包,并显示在控制台;
⑤ 释放资源。
public class UdpReceiveDemo {
public static void main(String[] args) throws IOException {
// 创建接收端Socket对象
DatagramSocket ds = new DatagramSocket(10086);
// 创建一个数据包(接收容器)
byte[] bys = new byte;
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);
// 调用Socket对象的接收方法接收数据
ds.receive(dp); // 阻塞式
// 解析数据包,并显示在控制台
InetAddress address = dp.getAddress();// 获取对方的ip
String ip = address.getHostAddress();
byte[] bys2 = dp.getData(); // 获取数据缓冲区
int len = dp.getLength(); // 获取数据的实际长度
String s = new String(bys2, 0, len);
System.out.println(ip + "传递的数据是:" + s);
// 释放资源
ds.close();
}
}4. 多线程结合收发UDP数据包
// ***********发送UDP数据报类
public class UdpSendThread implements Runnable {
private DatagramSocket ds;
public SendThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
// 封装键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("886".equals(line)) {
break;
}
// 创建数据并打包
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.12.255"), 12306);
// 发送数据
ds.send(dp);
}
// 释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// ***********接受UDP数据报类
public class ReceiveThread implements Runnable {
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
while (true) {
// 创建一个包裹
byte[] bys = new byte;
DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收数据
ds.receive(dp);
// 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println("from " + ip + " data is : " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// ***********测试类
public class ChatRoom {
public static void main(String[] args) throws IOException {
DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(12306);
SendThread st = new SendThread(dsSend);
ReceiveThread rt = new ReceiveThread(dsReceive);
Thread t1 = new Thread(st);
Thread t2 = new Thread(rt);
t1.start();
t2.start();
}
}3、TCP通讯
1. 相关API
Socket类: --- TCP客户端套接字
public Socket(InetAddress address, int port) --------> 创建一个流套接字并将其连接到指定 IP 地址的指定端口号
public InetAddress getInetAddress()----------------->返回套接字连接的地址。
public InputStream getInputStream()---------------->返回此套接字的输入流。
public OutputStream getOutputStream()------------>返回此套接字的输出流。
public void shutdownOutput()--------------------------> 通知对方套接字写入结束。
ServerSocket类: --- TCP服务器套接字
public ServerSocket(int port)-------------------------->创建绑定到特定端口的服务器套接字。
public Socket accept() ---------------------------------->侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
2. TCP客户端实现
步骤:
① 创建发送端的Socket对象;
② 这一步如果成功,就说明连接已经建立成功;
③ 获取输出流写数据,获取输入流读数据 ;
④ 释放资源;
以下以客户端向服务器上传文件为例:
注意:
读取文本文件时可以以null作为结束信息的,TCP流通道不能以null结束;
于是① 自定义结束标记;
② Socket对象提供了一种解决方案,public void shutdownOutput()
public class UdpUploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
BufferedReader br = new BufferedReader(new FileReader("123.txt"));
// 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
//自定义一个结束标记
//bw.write("over");
//bw.newLine();
//bw.flush();
//Socket提供了一个终止,它会通知服务器:客户端数据传输已结束
s.shutdownOutput();
// 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 释放资源
br.close();
s.close();
}
}3. TCP服务器实现
步骤:
① 创建接收端的Socket对象;
② 监听客户端连接。返回一个对应的Socket对象;
③ 获取输出流写数据,获取输入流读数据 ;
④ 释放资源。
public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器端的Socket对象,并绑定端口
ServerSocket ss = new ServerSocket(11111);
// 监听客户端连接
Socket s = ss.accept(); // 阻塞
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 封装文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.txt"));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
// if("over".equals(line)){ // 采用自定义“over”结束符
// break;
// }
bw.write(line);
bw.newLine();
bw.flush();
}
// 给出反馈
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
// 释放资源
bw.close();
s.close();
}
}4. TCP服务器多线程实现并发
支持服务器能够被多个客户端连接。
// **********服务器线程类
public class UserUdpThread implements Runnable {
private Socket s;
public UserUdpThread (Socket s) {
this.s = s;
}
@Override
public void run() {
try {
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 封装文本文件
// BufferedWriter bw = new BufferedWriter(newFileWriter("Copy.txt"));
// 为了防止名称冲突
String newName = System.currentTimeMillis() + ".txt";
BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// 给出反馈
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
// 释放资源
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// **********服务器
public class UploadUdpServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(11111);
while (true) {
Socket s = ss.accept();
new Thread(new UserUdpThread(s)).start();
}
}
} {:10_257:} 不错的内容 能写多一点就好了 public class UserUdpThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
构造函数拼写错误l erh 发表于 2019-8-27 21:07
public class UserUdpThread implements Runnable {
private Socket s;
 ...
谢谢提醒,已修正。
页:
[1]