InetAddress
类【重点】
继承关系图和构造器
InetAddress
类常用方法
1.getLocalHost 获取本机InetAddress对象
2.getByName 根据指定主机名、域名获取IP地址对象
3.getHostName 获取InetAddress对象的主机名
4.getHostAddress 获取InetAddress对象的地址
static InetAddress | getLocalHost() 返回本地主机的地址。 |
---|
String | getHostAddress() 返回文本显示中的IP 地址字符串。 |
---|---|
String | getHostName() 获取此IP 地址的主机名。 |
static InetAddress | getByName(String host) 确定主机名称的IP 地址。 |
---|
InetAddress
类作用
InetAddress
类的两大作用:
- 获取本机的信息【主机名/
IP
】 - 通过域名获取远程服务器【或其他主机】的
IP
package network_.inerAddress_;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
* 演示 InetAddress类常用方法
*/
public class InetAddress1 {
public static void main(String[] args) throws UnknownHostException {
// 使用InetAddress 类的静态方法 getLocalHost 获取一个 InetAddress 对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println("本机名称和IP地址= " + localHost);
// 返回值是:本机名称和IP地址= DESKTOP-4KJDTLR/172.18.245.88
// 根据指定主机名获取 ip 地址对象 使用getByName 方法 返回一个 InetAddress 对象
InetAddress byName = InetAddress.getByName("172.18.245.88");
System.out.println("byName = " + byName);
// 返回值是:byName = /172.18.245.88
// 根据指定域名获取 ip 地址 使用 getByName 方法 返回一个 InetAddress 对象
InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println("baidu = "+baidu);
// 返回值是:baidu = www.baidu.com/14.215.177.39
// 获取主机名 使用 getHostName 方法 返回一个主机名 或者 域名
String hostName = baidu.getHostName();
System.out.println("hostName = " +hostName );
// 返回值:hostName = www.baidu.com
// 获取对象的地址 使用 getHostAddress 方法 返回一个 IP 地址
String hostAddress = baidu.getHostAddress();
System.out.println("hostAddress = " + hostAddress);
// 返回值:hostAddress = 14.215.177.39
}
}
package com.hspedu.api;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 演示InetAddress 类的使用
*/
public class API_ {
public static void main(String[] args) throws UnknownHostException {
//1. 获取本机的InetAddress 对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);//DESKTOP-S4MP84S/192.168.12.1
//2. 根据指定主机名 获取 InetAddress对象
InetAddress host1 = InetAddress.getByName("DESKTOP-S4MP84S");
System.out.println("host1=" + host1);//DESKTOP-S4MP84S/192.168.12.1
//3. 根据域名返回 InetAddress对象, 比如 www.baidu.com 对应
InetAddress host2 = InetAddress.getByName("www.baidu.com");
System.out.println("host2=" + host2);//www.baidu.com / 110.242.68.4
//4. 通过 InetAddress 对象,获取对应的地址
String hostAddress = host2.getHostAddress();//IP 110.242.68.4
System.out.println("host2 对应的ip = " + hostAddress);//110.242.68.4
//5. 通过 InetAddress 对象,获取对应的主机名/或者的域名
String hostName = host2.getHostName();
System.out.println("host2对应的主机名/域名=" + hostName); // www.baidu.com
}
}
Socket
基本介绍:
- 套接字(
Socket
)开发网络应用程序被广泛采用,以至于成为事实上的标准 - 通信的两端都要有
Socket
,是两台机器通信的端点 - 网络通信其实就是
Socket
间的通信 Socket
允许程序把网络连接当成一个流,数据在两个Socket
通过IO
传输- 一般主动发起通信应用程序属于客户端,等待通信请求的为服务端
Socket
的理解
TCP
网络通信编程【非常重要】
基本介绍:
- 基于客户端 和 服务端的网络通信
- 底层使用的是
TCP/IP
协议 - 应用场景举例:客户端发送数据,服务端接受并显示控制台
- 基于
Socket
的TCP编程
或UDP编程
ServerSocket
类
继承关系图和构造器
构造器
Constructor and Description |
---|
ServerSocket() 创建未绑定的服务器套接字。 |
ServerSocket(int port) 创建绑定到指定端口的服务器套接字,创建一个监听指定端口服务器对象 |
ServerSocket(int port, int backlog) 创建服务器套接字并将其绑定到指定的本地端口号,并指定了积压。 |
ServerSocket(int port, int backlog, InetAddress bindAddr) 创建一个具有指定端口的服务器,侦听backlog和本地IP 地址绑定。 |
常用方法
Modifier and Type | Method and Description |
---|---|
Socket | accept() 侦听要连接到此套接字并接受它,获取一个连接 |
void | bind(SocketAddress endpoint) 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 |
void | bind(SocketAddress endpoint, int backlog) 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 |
void | close() 关闭此套接字。 |
ServerSocketChannel | getChannel() 返回与此套接字相关联的唯一的ServerSocketChannel 对象(如果有)。 |
InetAddress | getInetAddress() 返回此服务器套接字的本地地址。 |
int | getLocalPort() 返回此套接字正在侦听的端口号,返回正在监听端口 > |
SocketAddress | getLocalSocketAddress() 返回此套接字绑定到的端点的地址。 |
int | getReceiveBufferSize() 获取此 ServerSocket 的 SO_RCVBUF 选项的值,即将用于从该 ServerSocket 接受的套接字的建议缓冲区大小。 |
boolean | getReuseAddress() 测试是否启用了 SO_REUSEADDR 。 |
int | getSoTimeout() 检索 SO_TIMEOUT 的设置。 |
protected void | implAccept(Socket s) ServerSocket 的子类使用这个方法来覆盖accept()来返回自己的套接字子类。 |
boolean | isBound() 返回ServerSocket 的绑定状态。 |
boolean | isClosed() 返回ServerSocket 的关闭状态。 |
void | setPerformancePreferences(int connectionTime, int latency, int bandwidth) 设置此ServerSocket 的性能首选项。 |
void | setReceiveBufferSize(int size) 设置从 ServerSocket 接受的套接字的 SO_RCVBUF 选项的默认建议值。 |
void | setReuseAddress(boolean on) 启用/禁用 SO_REUSEADDR 套接字选项。 |
static void | setSocketFactory(SocketImplFactory fac) 设置应用程序的服务器套接字实现工厂。 |
void | setSoTimeout(int timeout) 启用/禁用 SO_TIMEOUT 带有指定超时,以毫秒为单位。 |
String | toString() 将该套接字的实现地址和实现端口返回为 String 。 |
Socket
类
Socket
类继承关系图和构造器
构造器
Modifier | Constructor and Description |
---|---|
| Socket() 创建一个未连接的套接字,并使用系统默认类型的SocketImpl 。 |
| Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。 绑定指定服务器和指定端口 |
| Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建套接字并将其连接到指定的远程端口上指定的远程地址。 |
| Socket(Proxy proxy) 创建一个未连接的套接字,指定应该使用的代理类型(如果有的话),无论其他任何设置如何。 |
protected | Socket(SocketImpl impl) 使用用户指定的SocketImpl 创建一个未连接的Socket。 |
| Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。 |
| Socket(String host, int port, boolean stream) 已弃用 使用DatagramSocket 代替UDP 传输。 |
| Socket(String host, int port, InetAddress localAddr, int localPort) 创建套接字并将其连接到指定远程端口上的指定远程主机。 |
常用方法
OutputStream | getOutputStream() 返回此套接字的输出流。 |
---|---|
int | getPort() 返回此套接字连接到的远程端口号。 |
InetAddress | getInetAddress() 返回套接字所连接的地址。 |
---|---|
InputStream | getInputStream() 返回此套接字的输入流。 |
InetAddress | getLocalAddress() 获取套接字所绑定的本地地址。 |
---|---|
int | getLocalPort() 返回此套接字绑定到的本地端口号。 |
void | shutdownInput() 将此套接字的输入流放置在“流的末尾”。 设置结束标记 |
---|---|
void | shutdownOutput() 禁用此套接字的输出流。设置结束标记 |
应用案例:
思路分析:
服务端代码
package network_.inerAddress_.socket_;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author: 海康
* @version: 1.0
* 演示:服务器监听,并接收打印
*/
public class TCPServer01 {
public static void main(String[] args) throws IOException {
// 在本机的 9999 端口监听,等待连接
ServerSocket serverSocket= new ServerSocket(9999);
// 通过 accept 方法返回一个 Socket 对象
Socket socket = serverSocket.accept();
// 当没有客户连接 9999 端口时,程序会阻塞,等待连接
System.out.println("服务器的 Socket = " + socket.getClass());
// 获取一个 InputStream 读取数据
InputStream ips = socket.getInputStream();
// 读取客户端发来 数据
byte[] by = new byte[1024*8];
int length = 0;
while ((length = ips.read(by))!=-1){
System.out.println(new String(by,0,length));
}
// 在使用完成后,一定要关闭流 从内层向外层关闭
if (ips != null){
ips.close();
}
if (socket != null){
socket.close();
}
if (serverSocket != null){
serverSocket.close();
}
}
}
客户端代码
package network_.inerAddress_.socket_;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
* 演示:客户端
*/
public class TCPClient01 {
public static void main(String[] args) throws IOException {
// 连接服务端(IP + 端口) 连接上后,生成一个 Socket 对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 获取一个 OutputStream 流
OutputStream ops = socket.getOutputStream();
// 通过输出流 ,写入数据到 数据通道中
ops.write("hello Server".getBytes());
// 使用完成后,一定要关闭流,从内层流开始关闭
if (ops != null){
ops.close();
}
if (socket != null){
socket.close();
}
System.out.println("客户访问服务端,结束。。。");
}
}
应用案例2
服务器端
package network_.inerAddress_.socket_;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author: 海康
* @version: 1.0
*/
public class TCPServer02 {
public static void main(String[] args) throws IOException {
// 在本机的 9999 端口进行监听
ServerSocket socket = new ServerSocket(9999);
// 获取一个获取Socket对象 使用accept 方法
Socket accept = socket.accept();// 如果没有客户端进行连接程序直接阻塞在此处
System.out.println("服务器端的Socket运行态="+socket.getClass());
// 获取一个 InputStream 对象 读取客户端发送的信息
InputStream isp = accept.getInputStream();
int length = 0;
byte[] by = new byte[1024*8];
while ((length = isp.read(by))!=-1){
System.out.println(new String(by,0,length));
}
// 接收到客户端发来的信息后,给客户端发回数据
// 获取 OutputStream 对象
OutputStream ops = accept.getOutputStream();
ops.write("hello Client".getBytes());
// 设置一个结束标记
accept.shutdownInput();
// 关闭流 资源
if (ops != null){
ops.close();
}
if (isp != null){
isp.close();
}
if (accept != null){
accept.close();
}
System.out.println("服务器端退出程序!!!");
}
}
客户端代码
package network_.inerAddress_.socket_;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
*/
@SuppressWarnings({"all"})
public class TCPClient02 {
public static void main(String[] args) throws IOException {
// 连接服务器,获取一个请求返回一个 Socket 对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端Socket运行态="+socket.getClass());
// 获取一个 OutputStream
OutputStream ops = socket.getOutputStream();
// 写入数据
ops.write("hello Server".getBytes());
// 设置一个结束标记
socket.shutdownOutput();
// 获取一个 InputStream 对象 用于读取服务器发回数据
InputStream ips = socket.getInputStream();
byte[] by = new byte[1024*8];
int length = 0;
while ((length = ips.read(by))!= -1){
System.out.println(new String(by,0,length));
}
// 在使用完成后,一定要关闭流
if (ips != null){
ips.close();
}
if (ops != null){
ops.close();
}
if (socket != null){
socket.close();
}
System.out.println("客户端退出程序 !!!");
}
}
客户端代码
package com.hspedu.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* 客户端,发送 "hello, server" 给服务端
*/
@SuppressWarnings({"all"})
public class SocketTCP02Client {
public static void main(String[] args) throws IOException {
//思路
//1. 连接服务端 (ip , 端口)
//解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端 socket返回=" + socket.getClass());
//2. 连接上后,生成Socket, 通过socket.getOutputStream()
// 得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流,写入数据到 数据通道
outputStream.write("hello, server".getBytes());
// 设置结束标记
socket.shutdownOutput();
//4. 获取和socket关联的输入流. 读取数据(字节),并显示
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, readLen));
}
//5. 关闭流对象和socket, 必须关闭
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端退出.....");
}
}
服务器端代码
package com.hspedu.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端
*/
@SuppressWarnings({"all"})
public class SocketTCP02Server {
public static void main(String[] args) throws IOException {
//思路
//1. 在本机 的9999端口监听, 等待连接
// 细节: 要求在本机没有其它服务在监听9999
// 细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接..");
//2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务端 socket =" + socket.getClass());
//
//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
InputStream inputStream = socket.getInputStream();
//4. IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容.
}
//5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello, client".getBytes());
// 设置结束标记
socket.shutdownOutput();
//6.关闭流和socket
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();//关闭
}
}
应用案例3
注意是:在使用BufferedWriter
时,一定要刷新内容到管道中,否则不能写入数据,在写入结束标记有两种方式:writer.newLine()
// 换行符,注意需要接收方也要使用readLine()
的方式读取 或 这种方式写入结束标记:``shutdownOutput()`
服务器端代码
package network_.inerAddress_.socket_;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author: 海康
* @version: 1.0
*/
@SuppressWarnings({"all"})
public class TCPServer3 {
public static void main(String[] args) throws IOException {
// 使用 ServerSocket 监听 一个端口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器正在 9999 端口监听!!!");
// 获取一个连接
Socket accept = serverSocket.accept();
// 获取一个 InputStream 对象
InputStream isp = accept.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(isp));
String line = "";
while ((line = br.readLine())!=null){
System.out.println(line);
}
// 获取一个 OutputStream 对象
OutputStream ops = accept.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ops));
bw.write("hello Clinet 字符流!!!");
// 写入后,一定要刷新管道,否则内容不能正常写入
bw.flush();
// 写入结束标记有两种方式:
// 方式一:
accept.shutdownInput();
// 方式二:
// bw.newLine();//注意用这种方式,要求对象在读取时,一定要使用 ReadLine 方式读取
// 关闭流 也是 只需要关闭外层 流
bw.close();
br.close();
accept.close();
serverSocket.close();
}
}
客户端代码
package network_.inerAddress_.socket_;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
*/
@SuppressWarnings({"all"})
public class TCPClient03 {
public static void main(String[] args) throws IOException {
// 连接服务器,获取 一个 Socket 对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 获取 一个写入对象 InputStream 并转成 BufferedWriter 对象
OutputStream ops = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ops));
bw.write("hello server 字符流");
// 写入后 一定要刷新 否则内容进入管道
bw.flush();
// 写入结束标记有两种方式
// 方式一:
socket.shutdownOutput();
// 方式二:
// bw.newLine();// 注意是这种方式要求对方 一定要使用 ReadLine 方式读取
// 获取 InputStream 对象
InputStream ips = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(ips));
String line = "";
while ((line= br.readLine())!= null){
System.out.println(line);
}
// 关闭流,只需要关闭外层 流 后开先关
bw.close();
br.close();
socket.close();
System.out.println("客户端结束 !!!");
}
}
package com.hspedu.socket;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* 客户端,发送 "hello, server" 给服务端, 使用字符流
*/
@SuppressWarnings({"all"})
public class SocketTCP03Client {
public static void main(String[] args) throws IOException {
//思路
//1. 连接服务端 (ip , 端口)
//解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端 socket返回=" + socket.getClass());
//2. 连接上后,生成Socket, 通过socket.getOutputStream()
// 得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流,写入数据到 数据通道, 使用字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello, server 字符流");
bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!
bufferedWriter.flush();// 如果使用的字符流,需要手动刷新,否则数据不会写入数据通道
//4. 获取和socket关联的输入流. 读取数据(字符),并显示
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
//5. 关闭流对象和socket, 必须关闭
bufferedReader.close();//关闭外层流
bufferedWriter.close();
socket.close();
System.out.println("客户端退出.....");
}
}
package com.hspedu.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端, 使用字符流方式读写
*/
@SuppressWarnings({"all"})
public class SocketTCP03Server {
public static void main(String[] args) throws IOException {
//思路
//1. 在本机 的9999端口监听, 等待连接
// 细节: 要求在本机没有其它服务在监听9999
// 细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接..");
//2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务端 socket =" + socket.getClass());
//
//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
InputStream inputStream = socket.getInputStream();
//4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);//输出
//5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
// 使用字符输出流的方式回复信息
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello client 字符流");
bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
bufferedWriter.flush();//注意需要手动的flush
//6.关闭流和socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();//关闭
}
}
上传文件
应用案例4
思路分析:
下面的代码存在Bug
package network_.inerAddress_.socket_;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
*/
public class TCPFIleClient01 {
public static void main(String[] args) throws IOException {
// 请求服务器 获取连接
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 读取一个文件【图片】
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\rose.jpg"));
// 获取一个 getOutputStream 对象
OutputStream ops = socket.getOutputStream();
BufferedOutputStream bop = new BufferedOutputStream(ops);
int length = 0;
byte[] by = new byte[1024*8];
while ((length = bis.read(by))!=-1){
bop.write(by,0,length);
}
// 结束标记
socket.shutdownOutput();
InputStream ips = socket.getInputStream();
BufferedInputStream bip = new BufferedInputStream(ips);
int le = 0;
byte[] bytes = new byte[1024*8];
while ((le=bip.read(bytes))!=-1){
System.out.println(new String(bytes,0,le));
}
// 关闭流
bip.close();
bis.close();
ops.close();
socket.close();
System.out.println("客户端结束 !!! ");
}
}
package network_.inerAddress_.socket_;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
/**
* @author: 海康
* @version: 1.0
*/
public class TCPFileServer01 {
public static void main(String[] args) throws IOException {
// 服务器在 8888 端口监听
ServerSocket serverSocket = new ServerSocket(8888);
// 获取到一个连接
Socket accept = serverSocket.accept();
System.out.println("服务器在 8888 端口监听!!!");
// 获取一个输入流
InputStream ips = accept.getInputStream();
BufferedInputStream bis = new BufferedInputStream(ips);
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("src\\myRose.jpg"));
byte by[] = new byte[1024*8];
int length = 0;
while ((length = bis.read(by))!=-1){
bos.write(by,0,length);
}
// 写完数据后,获取一个输出流
OutputStream ops = accept.getOutputStream();
ops.write("收到图片".getBytes());
// 如果在使用 Buffered字符流,一定要刷新
accept.shutdownOutput();
// 关闭流
ops.close();
bos.close();
bis.close();
accept.close();
serverSocket.close();
System.out.println("服务器端结束 !!! ");
}
}
优化代码:
package network_.inerAddress_.socket_.upload_;
import java.io.*;
/**
* @author: 海康
* @version: 1.0
*/
public class StreamUtils {
/**
* 功能:将输入流转换成byte[]
* @param is
* @return
* @throws IOException
*/
public static byte[] streamToByArray(InputStream is) throws IOException {
// 创建一个 ByteArrayOutputStream 对象用于存储读取到的数据
ByteArrayOutputStream baop = new ByteArrayOutputStream();
byte[] by = new byte[1024*8];
int length = 0;
while ((length=is.read(by))!=-1){
baop.write(by,0,length);
}
byte[] bytes = baop.toByteArray();
// 使用完成后,关闭流
if (baop!=null)
baop.close();
return bytes;
}
/**
* 功能:将InputStream转换成String
* @param is
* @return
* @throws IOException
*/
public static String streamToString(InputStream is) throws IOException {
// 创建一个读取对象
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
// 创建一个 StringBuilder 对象
StringBuilder sb = new StringBuilder();
String line = "";
while ((line=reader.readLine())!=null){
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
}
}
package network_.inerAddress_.socket_.upload_;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author: 海康
* @version: 1.0
*/
public class TCPFileServer01 {
public static void main(String[] args) throws IOException {
// 服务器端在 8888 端口监听
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器端在 8888 端口监听!!!");
// 获取一个 连接
Socket accept = serverSocket.accept();
// 获取一个 InputStream 对象 读取数据
InputStream inputStream = accept.getInputStream();
byte[] bytes = StreamUtils.streamToByArray(inputStream);
// 写入到指定位置
String copyFilePath = "src\\myRose3.jpg";
BufferedOutputStream bs = new BufferedOutputStream(new FileOutputStream(copyFilePath));
bs.write(bytes);
// 获取一个 OutputStream 对象
OutputStream outputStream = accept.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("图片收到");
// 记得一定要刷新内容,否则内容无法进入管道
writer.flush();
// 设置结束标记
accept.shutdownOutput();
// 关闭流
writer.close();
bs.close();
inputStream.close();
accept.close();
serverSocket.close();
}
}
package network_.inerAddress_.socket_.upload_;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
*/
public class TCPFileClient01 {
public static void main(String[] args) throws IOException {
// 获取一个 服务器端对象 Socket
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 读取图片
String filePath = "e:\\rose.jpg";
FileInputStream fileInputStream = new FileInputStream(filePath);
byte[] bytes = StreamUtils.streamToByArray(fileInputStream);
// 获取一个写入管道对象
OutputStream outputStream = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
bos.write(bytes);
// 设置结束标记
socket.shutdownOutput();
// 获取服务器端回话
InputStream inputStream = socket.getInputStream();
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
// 关闭流
inputStream.close();
bos.close();
fileInputStream.close();
socket.close();
}
}
优化代码2
package com.hspedu.upload;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 此类用于演示关于流的读写方法
*
*/
public class StreamUtils {
/**
* 功能:将输入流转换成byte[]
* @param is
* @return
* @throws Exception
*/
public static byte[] streamToByteArray(InputStream is) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
byte[] b = new byte[1024];
int len;
while((len=is.read(b))!=-1){
bos.write(b, 0, len);
}
byte[] array = bos.toByteArray();
bos.close();
return array;
}
/**
* 功能:将InputStream转换成String
* @param is
* @return
* @throws Exception
*/
public static String streamToString(InputStream is) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder= new StringBuilder();
String line;
while((line=reader.readLine())!=null){ //当读取到 null时,就表示结束
builder.append(line+"\r\n");
}
return builder.toString();
}
}
package com.hspedu.upload;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 文件上传的服务端
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
//1. 服务端在本机监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在8888端口监听....");
//2. 等待连接
Socket socket = serverSocket.accept();
//3. 读取客户端发送的数据
// 通过Socket得到输入流
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//4. 将得到 bytes 数组,写入到指定的路径,就得到一个文件了
String destFilePath = "src\\abc.mp4";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
bos.close();
// 向客户端回复 "收到图片"
// 通过socket 获取到输出流(字符)
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("收到图片");
writer.flush();//把内容刷新到数据通道
socket.shutdownOutput();//设置写入结束标记
//关闭其他资源
writer.close();
bis.close();
socket.close();
serverSocket.close();
}
}
package com.hspedu.upload;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* 文件上传的客户端
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
//客户端连接服务端 8888,得到Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//创建读取磁盘文件的输入流
//String filePath = "e:\\qie.png";
String filePath = "e:\\abc.mp4";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
//bytes 就是filePath对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
//通过socket获取到输出流, 将bytes数据发送给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道
bis.close();
socket.shutdownOutput();//设置写入数据的结束标记
//=====接收从服务端回复的消息=====
InputStream inputStream = socket.getInputStream();
//使用StreamUtils 的方法,直接将 inputStream 读取到的内容 转成字符串
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
//关闭相关的流
inputStream.close();
bos.close();
socket.close();
}
}
netstat
指令【重点】
1. netstat -an // 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
2. netstat -an | more // 可以分页显示
3. netstat -anb // 可以查看当机主机网络情况和那个应用程序在监听【内容显示更加全】【前提是需要管理员权限】
netstat -anb | more
查看的效果
TCP
网络通讯端口问题【重点】
当客户端连接到服务端后,实际上客户端是通过一个端口和服务端进行通讯的,这个端是TCP/IP
来分配的,是不确定的,是随机的,意思就是客户端也有一个端口,这个端口是TCP/CP
分配的,是随机的;不像服务器端的端口是固定的
UDP
网络通信编程
基本介绍
1.类DatagramSocket
【数据报套接字】 和 DatagramPacket
【数据包/数据报】实现了基于UDP
协议网络程序
2.UDP
数据报通过数据报套接字 DatagramSocket
发送 和 接收,系统不保证UDP
数据报一定能名安全送到目的地,也不能确定什么时候可以抵达
3.DatagramPacket
对象封装了UDP
数据报,在数据报中包含了发送端的IP
地址和端口号以及接收端的IP
地址和端口号
4.UDP
协议中每个数据报都给出了完整地址信息,因此无须建立发送方和接收方的连接
基本流程
- 核心的两个类【对象】
DatagramSocket
与DatagramPacket
- 建立发送端,接收端【没有服务端和客户端概念】
- 发送数据前,建立数据包【数据报】
DatagramPacket
对象 - 调用
DatagramSocket
的发送,接收方法 - 关闭
DatagramSocket
UDP
网络编程原理示意图
DatagramSocket
类
继承关系和构造器
构造器
Modifier | Constructor and Description |
---|---|
| DatagramSocket() 构造数据报套接字并将其绑定到本地主机上的任何可用端口。 |
protected | DatagramSocket(DatagramSocketImpl impl) 使用指定的DatagramSocketImpl 创建一个未绑定的数据报套接字。 |
| DatagramSocket(int port) 构造数据报套接字并将其绑定到本地主机上的指定端口。 |
| DatagramSocket(int port, InetAddress laddr) 创建一个数据报套接字,绑定到指定的本地地址。 |
| DatagramSocket(SocketAddress bindaddr) 创建一个数据报套接字,绑定到指定的本地套接字地址。 |
常用方法
void | receive(DatagramPacket p) 从此套接字接收数据报包。 |
---|---|
void | send(DatagramPacket p) 从此套接字发送数据报包。 |
DatagramPacket
类
继承关系和构造器
构造器
Constructor and Description |
---|
DatagramPacket(byte[] buf, int length) 构造一个 DatagramPacket 用于接收长度的数据包 length 。 |
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造用于发送长度的分组的数据报包 length 指定主机上到指定的端口号。 |
DatagramPacket(byte[] buf, int offset, int length) 构造一个 DatagramPacket 用于接收长度的分组 length ,指定偏移到缓冲器中。 |
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 构造用于发送长度的分组数据报包 length 具有偏移 ioffset 指定主机上到指定的端口号。 |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造用于发送长度的分组数据报包 length 具有偏移 ioffset 指定主机上到指定的端口号。 |
DatagramPacket(byte[] buf, int length, SocketAddress address) 构造用于发送长度的分组的数据报包 length 指定主机上到指定的端口号。 |
方法
Modifier and Type | Method and Description |
---|---|
InetAddress | getAddress() 返回该数据报发送或接收数据报的计算机的IP地址。 |
byte[] | getData() 返回数据缓冲区。 |
int | getLength() 返回要发送的数据的长度或接收到的数据的长度。 |
int | getOffset() 返回要发送的数据的偏移量或接收到的数据的偏移量。 |
int | getPort() 返回发送数据报的远程主机上的端口号,或从中接收数据报的端口号。 |
SocketAddress | getSocketAddress() 获取该数据包发送到或正在从其发送的远程主机的SocketAddress(通常为IP地址+端口号)。 |
void | setAddress(InetAddress iaddr) 设置该数据报发送到的机器的IP地址。 |
void | setData(byte[] buf) 设置此数据包的数据缓冲区。 |
void | setData(byte[] buf, int offset, int length) 设置此数据包的数据缓冲区。 |
void | setLength(int length) 设置此数据包的长度。 |
void | setPort(int iport) 设置发送此数据报的远程主机上的端口号。 |
void | setSocketAddress(SocketAddress address) 设置该数据报发送到的远程主机的SocketAddress (通常是IP 地址+端口号)。 |
应用案例
package network_.inerAddress_.UDP_;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* @author: 海康
* @version: 1.0
*/
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
// 接收端A 在 本机 9999 端监听 接收数据
DatagramSocket socket = new DatagramSocket(9999);
// 需要创建 DatagramPacket 对象 用于接收数据
// 创建一个 byte 数组用于构建 DatagramPacket 对象
byte[] bytes = new byte[1024*64];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
// 在 receiver 接收到的数据会填充到 packet 中
// 如果没有接收到数据程序会一直阻塞在此处
socket.receive(packet);
// 获取到接收数据的长度
int length = packet.getLength();
// 获取数据
byte[] data = packet.getData();
// 创建一个字符串,打印出信息
String s = new String(data, 0, length);
System.out.println(s);
// 接收到数据到向发送端回话
byte[] bytes1 = "好的 明天见!!!".getBytes();
DatagramPacket packet1 = new
DatagramPacket(bytes1, bytes1.length,
InetAddress.getByName("127.0.0.1"), 9998);
socket.send(packet1);
// 关闭流
socket.close();
System.out.println("程序A 退出!!!");
}
}
package network_.inerAddress_.UDP_;
import java.io.IOException;
import java.net.*;
/**
* @author: 海康
* @version: 1.0
*/
public class UDPSendB {
public static void main(String[] args) throws IOException {
// 创建一个DatagramSocket 对象并在 9998 端口监听
DatagramSocket socket = new DatagramSocket(9998);
// 创建一个DatagramPacket 对象用于封装数据
byte[] bytes = "hello 明天去吃火锅?".getBytes();
DatagramPacket packet =
new DatagramPacket(bytes, bytes.length,
InetAddress.getByName("127.0.0.1"),9999);
// 使用 send 方法进行发送
socket.send(packet);
// 创建一个 DatagramPacket 对象用于接收数据
byte[] bytes1 = new byte[1024*8];
DatagramPacket packet1 = new DatagramPacket(bytes1, bytes1.length);
socket.receive(packet1);
int length = packet1.getLength();
byte[] data = packet1.getData();
String s = new String(data, 0, length);
System.out.println(s);
// 发送完成后 关闭流
socket.close();
System.out.println("程序B 退出!!!");
}
}
练习题目
package network_.inerAddress_.homeWork_;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author: 海康
* @version: 1.0
*/
public class HomeWork01Client {
public static void main(String[] args) throws IOException {
// 获取一个连接 就是请求服务器
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 获取一个 OutputStream 对象
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write("hobby");
bw.flush();// 一定要刷新内容,否则内容无法进入管道中
socket.shutdownOutput();// 设置一个结束标记
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String lien = "";
while ((lien=br.readLine())!=null){
System.out.println(lien);
}
// 关闭流
br.close();
bw.close();
socket.close();
System.out.println("客户端结束 !!!");
}
}
package network_.inerAddress_.homeWork_;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author: 海康
* @version: 1.0
*/@SuppressWarnings({"all"})
public class HomeWork01Server {
public static void main(String[] args) throws IOException {
// 服务器在 9999 端监听
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器在 9999 端口监听!!!");
// 获取一个连接
Socket accept = serverSocket.accept();
// 获取一个 OutputStream 对象
OutputStream outputStream = accept.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
// 获取一个 InputStream 对象
InputStream inputStream = accept.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String lent = "";
while ((lent = br.readLine())!=null){
if (lent.equals("name")){
writer.write("我是服务器nova!!!");
}else if (lent.equals("hobby")){
writer.write("编写java程序 哈哈!!!");
}else {
writer.write("你说啥呢?");
}
// 刷新内容
writer.flush();
System.out.println(lent);
}
// 设置结束标记
accept.shutdownOutput();
// 关闭流
br.close();
writer.close();
accept.close();
serverSocket.close();
System.out.println("服务端结束 !!!");
}
}
package com.hspedu.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端, 使用字符流方式读写
*/
@SuppressWarnings({"all"})
public class Homework01Server {
public static void main(String[] args) throws IOException {
//思路
//1. 在本机 的9999端口监听, 等待连接
// 细节: 要求在本机没有其它服务在监听9999
// 细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接..");
//2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
//
//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
InputStream inputStream = socket.getInputStream();
//4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
String answer = "";
if ("name".equals(s)) {
answer = "我是明天";
} else if("hobby".equals(s)) {
answer = "编写java程序";
} else {
answer = "你说的啥子";
}
//5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
// 使用字符输出流的方式回复信息
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(answer);
bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
bufferedWriter.flush();//注意需要手动的flush
//6.关闭流和socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();//关闭
}
}
package com.hspedu.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* 客户端,发送 "hello, server" 给服务端, 使用字符流
*/
@SuppressWarnings({"all"})
public class Homework01Client {
public static void main(String[] args) throws IOException {
//思路
//1. 连接服务端 (ip , 端口)
//解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//2. 连接上后,生成Socket, 通过socket.getOutputStream()
// 得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3. 通过输出流,写入数据到 数据通道, 使用字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
//从键盘读取用户的问题
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的问题");
String question = scanner.next();
bufferedWriter.write(question);
bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!
bufferedWriter.flush();// 如果使用的字符流,需要手动刷新,否则数据不会写入数据通道
//4. 获取和socket关联的输入流. 读取数据(字符),并显示
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
//5. 关闭流对象和socket, 必须关闭
bufferedReader.close();//关闭外层流
bufferedWriter.close();
socket.close();
System.out.println("客户端退出.....");
}
}
package network_.inerAddress_.homeWork_;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
/**
* @author: 海康
* @version: 1.0
*/
public class HomeWork02Send {
public static void main(String[] args) throws IOException {
// 创建 DatagramSocket 对象 并在 9999 监听
DatagramSocket socket = new DatagramSocket(9999);
Scanner sc = new Scanner(System.in);
System.out.println("请您输入您的问题?");
String s = sc.nextLine();
byte[] bytes = s.getBytes();
// 获取 DatagramPacket 对象 用于封装数据
DatagramPacket datagramPacket = new DatagramPacket(bytes,
bytes.length, InetAddress.getByName("127.0.0.1"),8888);
socket.send(datagramPacket);
// 创建一个 DatagramPacket 对象用于接收数据
byte[] bytes1 = new byte[1024*8];
DatagramPacket packet = new DatagramPacket(bytes1, bytes1.length);
socket.receive(packet);// 接收数据填充到 packet 中
// 拆包取出数据
System.out.println(new String(packet.getData(),0,packet.getLength()));
// 关闭流
socket.close();
System.out.println("发送端 结束 哈哈!!!");
}
}
package network_.inerAddress_.homeWork_;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* @author: 海康
* @version: 1.0
*/
public class HomeWork02Receiver {
public static void main(String[] args) throws IOException {
// 创建一个 DatagramSocket 对象 并且在 8888 端品监听
DatagramSocket socket = new DatagramSocket(8888);
// 创建一个 DatagramPacket 对象 用于封装数据
byte[] bytes = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.receive(packet);// 接收到数据会填充到 packet 中
String s = new String(packet.getData(), 0,packet.getLength());
// 重新创建一个 DatagramPacket 对象 用于封装数据用于发送
DatagramPacket datagramPacket = null;
if (s.equals("四大名著是哪些?")){
byte[] bytes1 = "《红楼梦》,《西游记》,...".getBytes();
datagramPacket = new DatagramPacket(bytes1,
bytes1.length, InetAddress.getByName("127.0.0.1"),9999);
socket.send(datagramPacket);
}else {
byte[] bytes1 = "what?".getBytes();
datagramPacket = new DatagramPacket(bytes1,
bytes1.length ,InetAddress.getByName("127.0.0.1"),9999 );
socket.send(datagramPacket);
}
// 关闭流
socket.close();
System.out.println("接收方结束 !!!");
}
}
package com.hspedu.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP接收端
*/
@SuppressWarnings({"all"})
public class Homework02ReceiverA {
public static void main(String[] args) throws IOException {
//1. 创建一个 DatagramSocket 对象,准备在8888接收数据
DatagramSocket socket = new DatagramSocket(8888);
//2. 构建一个 DatagramPacket 对象,准备接收数据
// 在前面讲解UDP 协议时,说过一个数据包最大 64k
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
// 填充到 packet对象
System.out.println("接收端 等待接收问题 ");
socket.receive(packet);
//4. 可以把packet 进行拆包,取出数据,并显示.
int length = packet.getLength();//实际接收到的数据字节长度
byte[] data = packet.getData();//接收到数据
String s = new String(data, 0, length);
//判断接收到的信息是什么
String answer = "";
if("四大名著是哪些".equals(s)) {
answer = "四大名著 <<红楼梦>> <<三国演示>> <<西游记>> <<水浒传>>";
} else {
answer = "what?";
}
//===回复信息给B端
//将需要发送的数据,封装到 DatagramPacket对象
data = answer.getBytes();
//说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
packet =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9998);
socket.send(packet);//发送
//5. 关闭资源
socket.close();
System.out.println("A端退出...");
}
}
package com.hspedu.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* 发送端B ====> 也可以接收数据
*/
@SuppressWarnings({"all"})
public class Homework02SenderB {
public static void main(String[] args) throws IOException {
//1.创建 DatagramSocket 对象,准备在9998端口 接收数据
DatagramSocket socket = new DatagramSocket(9998);
//2. 将需要发送的数据,封装到 DatagramPacket对象
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的问题: ");
String question = scanner.next();
byte[] data = question.getBytes(); //
//说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
DatagramPacket packet =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 8888);
socket.send(packet);
//3.=== 接收从A端回复的信息
//(1) 构建一个 DatagramPacket 对象,准备接收数据
// 在前面讲解UDP 协议时,说过一个数据包最大 64k
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
//(2) 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
// 填充到 packet对象
// 提示: 当有数据包发送到 本机的9998端口时,就会接收到数据
// 如果没有数据包发送到 本机的9998端口, 就会阻塞等待.
socket.receive(packet);
//(3) 可以把packet 进行拆包,取出数据,并显示.
int length = packet.getLength();//实际接收到的数据字节长度
data = packet.getData();//接收到数据
String s = new String(data, 0, length);
System.out.println(s);
//关闭资源
socket.close();
System.out.println("B端退出");
}
}
文件下载
思路分析
代码区:
package network_.inerAddress_.homeWork_;
import java.io.*;
/**
* @author: 海康
* @version: 1.0
*/
@SuppressWarnings({"all"})
public class StreamUtils {
/**
* 功能:将输入流转换成byte[]
* @param is
* @return
* @throws IOException
*/
public static byte[] streamToByArray(InputStream is) throws IOException {
// 创建一个 ByteArrayOutputStream 对象用于存储读取到的数据
ByteArrayOutputStream baop = new ByteArrayOutputStream();
byte[] by = new byte[1024*8];
int length = 0;
while ((length=is.read(by))!=-1){
baop.write(by,0,length);
}
byte[] bytes = baop.toByteArray();
// 使用完成后,关闭流
if (baop!=null)
baop.close();
return bytes;
}
/**
* 功能:将InputStream转换成String
* @param is
* @return
* @throws IOException
*/
public static String streamToString(InputStream is) throws IOException {
// 创建一个读取对象
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
// 创建一个 StringBuilder 对象
StringBuilder sb = new StringBuilder();
String line = "";
while ((line=reader.readLine())!=null){
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
}
}
package network_.inerAddress_.homeWork_;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* @author: 海康
* @version: 1.0
*/
public class HomeWork03Server {
public static void main(String[] args) throws IOException {
// 创建一个 ServerSocket 并且在 9999 端口监听
ServerSocket serverSocket = new ServerSocket(9999);
// 获取一个连接 返回一个 Socket 对象
Socket accept = serverSocket.accept();
// 获取一个 InputStream 对象
InputStream inputStream = accept.getInputStream();
String s = StreamUtils.streamToString(inputStream);
// 文件的路径
String parentPath = "src//";
String childrenPath = "";
if (s.equals("高山流水")) {
childrenPath = "高山流水"+".mp3";
}else {
childrenPath = "无名"+".mp3";
}
File file = new File(parentPath, childrenPath);
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bytes = StreamUtils.streamToByArray(fileInputStream);
// 获取一个 OutputStream 对象
OutputStream outputStream = accept.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
bos.write(bytes);
accept.shutdownOutput();// 设置结束标记
// 关闭流
bos.close();
fileInputStream.close();
accept.close();
serverSocket.close();
System.out.println("服务器端结束 !!!");
}
}
package network_.inerAddress_.homeWork_;
import org.junit.platform.commons.util.StringUtils;
import java.awt.*;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* @author: 海康
* @version: 1.0
*/
public class HomeWork03Client {
public static void main(String[] args) throws IOException {
// 创建Socket 对象 获取服务器的连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
// 获取 OutputStream 对象
OutputStream outputStream = socket.getOutputStream();
// 输入一个要下载文件名
Scanner sc = new Scanner(System.in);
System.out.println("请您输入要下载的文件名!");
String s = sc.nextLine();
outputStream.write(s.getBytes());
// 设置结束标记
socket.shutdownOutput();
// 获取 InputStream 对象
InputStream inputStream = socket.getInputStream();
byte[] bytes = StreamUtils.streamToByArray(inputStream);
// 创建一个 BufferedOutputStream 对象 将读取到文件写到磁盘中
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\myMp3.mp3"));
bos.write(bytes);
// 使用完成后 关闭流
bos.close();
inputStream.close();
socket.close();
// 完成
System.out.println("客户端结束 !!!");
}
}
代码2
package com.hspedu.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 文件下载的客户端
*/
public class Homework03Client {
public static void main(String[] args) throws Exception {
//1. 接收用户输入,指定下载文件名
Scanner scanner = new Scanner(System.in);
System.out.println("请输入下载文件名");
String downloadFileName = scanner.next();
//2. 客户端连接服务端,准备发送
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//3. 获取和Socket关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write(downloadFileName.getBytes());
//设置写入结束的标志
socket.shutdownOutput();
//4. 读取服务端返回的文件(字节数据)
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//5. 得到一个输出流,准备将 bytes 写入到磁盘文件
//比如你下载的是 高山流水 => 下载的就是 高山流水.mp3
// 你下载的是 无名 => 下载的就是 无名.mp3 文件名 无名.mp3
String filePath = "e:\\" + downloadFileName + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(bytes);
//6. 关闭相关的资源
bos.close();
bis.close();
outputStream.close();
socket.close();
System.out.println("客户端下载完毕,正确退出..");
}
}
package com.hspedu.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 先写文件下载的服务端
*/
public class Homework03Server {
public static void main(String[] args) throws Exception {
//1 监听 9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//2.等待客户端连接
System.out.println("服务端,在9999端口监听,等待下载文件");
Socket socket = serverSocket.accept();
//3.读取 客户端发送要下载的文件名
// 这里使用了while读取文件名,时考虑将来客户端发送的数据较大的情况
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downLoadFileName = "";
while ((len = inputStream.read(b)) != -1) {
downLoadFileName += new String(b, 0 , len);
}
System.out.println("客户端希望下载文件名=" + downLoadFileName);
//老师在服务器上有两个文件, 无名.mp3 高山流水.mp3
//如果客户下载的是 高山流水 我们就返回该文件,否则一律返回 无名.mp3
String resFileName = "";
if("高山流水".equals(downLoadFileName)) {
resFileName = "src\\高山流水.mp3";
} else {
resFileName = "src\\无名.mp3";
}
//4. 创建一个输入流,读取文件
BufferedInputStream bis =
new BufferedInputStream(new FileInputStream(resFileName));
//5. 使用工具类StreamUtils ,读取文件到一个字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
//6. 得到Socket关联的输出流
BufferedOutputStream bos =
new BufferedOutputStream(socket.getOutputStream());
//7. 写入到数据通道,返回给客户端
bos.write(bytes);
socket.shutdownOutput();//很关键.
//8 关闭相关的资源
bis.close();
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出...");
}
}
package com.hspedu.homework;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 此类用于演示关于流的读写方法
*
*/
public class StreamUtils {
/**
* 功能:将输入流转换成byte[]
* @param is
* @return
* @throws Exception
*/
public static byte[] streamToByteArray(InputStream is) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
byte[] b = new byte[1024];
int len;
while((len=is.read(b))!=-1){
bos.write(b, 0, len);
}
byte[] array = bos.toByteArray();
bos.close();
return array;
}
/**
* 功能:将InputStream转换成String
* @param is
* @return
* @throws Exception
*/
public static String streamToString(InputStream is) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder= new StringBuilder();
String line;
while((line=reader.readLine())!=null){
builder.append(line+"\r\n");
}
return builder.toString();
}
}