Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。
网络程序:能够接收另一台计算机发送过来的数据或能够向另一台计算机发送数据的程序。
Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
计算机网络 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源。
InetAddress
192.168.0.1
:
分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
InetAddress
类主要表示 IP 地址,两个子类:Inet4Address
、Inet6Address
InetAddress
类对象含有一个 Internet 主机地址的域名和IP地址InetAddress
类没有提供公共的构造器,而是提供了如下几个静态方法来获取 InetAddress
实例
public static InetAddress getLocalHost()
public static InetAddress getByName(String host)
InetAddress
提供了如下几个常用的方法
public String getHostAddress()
:返回 IP 地址字符串(以文本表现形式)public String getHostName()
:获取此 IP 地址的主机名public boolean isReachable(int timeout)
:测试是否可以达到该地址TCP/IP协议簇:TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层
[维基百科] socket 是计算机网络中用于在节点内发送或接收数据的内部端点。具体来说,它是网络软件 (协议栈) 中这个端点的一种表示,包含通信协议、目标地址、状态等,是系统资源的一种形式。
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字(Socket)。通信的两端都要有Socket,是两台机器间通信的端点。网络通信其实就是Socket间的通信。
Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输。一般主动发起通信的应用程序为 [客户端],等待通信请求的为 [服务端]。
客户端-服务器是一种最常见的网络应用程序模型。服务器是一个为其客户端提供某种特定服务的硬件或软件。客户机是一个用户应用程序,用于访问某台服务器提供的服务。端口号是对一个服务的访问场所,它用于区分同一物理计算机上的多个服务。套接字用于连接客户端和服务器,客户端和服务器之间的每个通信会话使用一个不同的套接字。TCP协议用于实现面向连接的会话。
Socket 分类:
Socket(String host,int port) throws UnknownHostException, IOException
:向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常Socket(InetAddress address, int port) throws IOException
:根据 InetAddress 对象所表示的 IP 地址以及端口号 port 发起连接getInputStream()
获得输入流,使用 getOutputStream()
获得输出流,进行数据传输ServerSocket(int port)
:创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求accept()
:监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象getOutputStream()
和 getInputStream()
:获取输出流和输入流,开始网络数据的发送和接收ServerSocket
对象负责等待客户端请求建立套接字连接,类似邮局某个窗口中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字连接的 ServerSocket
对象accept()
会返回一个 Socket 对象,这个方法是一个阻塞方法,如果没有客户连接,它将一直等待代码演示1:客户端向服务器端发句话
public class TCPDemo {
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
InetAddress inetAddress = null;
try {
// 1. 创建 Socket 对象,指明服务器的ip和端口号
inetAddress = InetAddress.getByName("127.0.0.1");
socket = new Socket(inetAddress, 6677);
// 2. 获取一个输出流,用于输出数据
os = socket.getOutputStream();
// 3. 写入数据
os.write("你好鸭,我是客户端".getBytes());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4. 关闭资源
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void sever() {
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
// 1. 创建服务器端的 serverSocket
ss = new ServerSocket(6677);
// 2. 等待接收来自客户端的socket
socket = ss.accept();
// 3. 获取输入流
is = socket.getInputStream();
// 传统读方式可能会导致乱码
baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int len;
// 4. 读取输入流中的数据
while((len = is.read(buf)) != -1)
baos.write(buf, 0, len);
System.out.println("收到了来自" + socket.getInetAddress().getHostAddress() + "的数据");
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. 关闭资源
if(baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
代码演示2:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端并关闭相应的连接
public class TCPDemo1 {
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
InputStream is = null;
InetAddress inetAddress = null;
ByteArrayOutputStream baos = null;
try {
// 1. 创建 Socket 对象,指明服务器的ip和端口号
inetAddress = InetAddress.getByName("127.0.0.1");
socket = new Socket(inetAddress, 6677);
// 2. 获取一个输出流,用于输出数据
os = socket.getOutputStream();
// 3. 写入数据
os.write("你好鸭,我是客户端".getBytes());
// 4. 关闭数据输出
socket.shutdownOutput();
// 5. 接收来自服务端的答复
is = socket.getInputStream();
baos = new ByteArrayOutputStream();
int len;
byte[] buf = new byte[1024];
while((len = is.read(buf)) != -1)
baos.write(buf, 0, len);
System.out.println(baos.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 7. 关闭资源
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void sever() {
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
BufferedOutputStream bos = null;
OutputStream os = null;
try {
// 1. 创建服务器端的 serverSocket
ss = new ServerSocket(6677);
// 2. 等待接收来自客户端的socket
socket = ss.accept();
// 3. 获取输入流
is = socket.getInputStream();
bos = new BufferedOutputStream(new FileOutputStream("陶源.png"));
byte[] buf = new byte[1024];
int len;
// 4. 读取输入流中的数据,然后写出到文件
while((len = is.read(buf)) != -1)
bos.write(buf, 0, len);
System.out.println("收到了来自" + socket.getInetAddress().getHostAddress() + "的数据");
// 5. 给客户端答复
os = socket.getOutputStream();
os.write("收到!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 6. 关闭资源
if(bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
read()
是一个阻塞函数,如果客户端没有声明断开 outputStream 那么它就会认为客户端仍旧可能发送数据,像 read()
这种阻塞读取函数还有 BufferedReader 中的 readLine()
、DataInputStream 中的 readUTF()
等。write()
时调用 shutdownOutput()
关闭输出流,这样对端的 inputStream
上的 read
操作就会返回 -1, 这里我们要注意下不能调用 socket.getInputStream().close()
。因为它会导致 socket 直接被关闭。 当然如果不需要继续在 socket 上进行读操作,也可以直接关闭 socket。但是这个方法不能用于通信双方需要多次交互的情况。DatagramSocket(int port)
创建一个数据报套接字,并绑定到指定端口上DatagramPacket(byte[] buf, int length)
建立一个字节数组以接收 UDP 包receive()
,接收 UDP 包close()
DatagramSocket()
创建一个数据报套接字DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
建立要发送的 UDP 包send()
,发送 UDP 包close()
@Test
public void send() {
DatagramSocket ds = null;
try {
// A:创建发送端的Socket对象
// DatagramSocket 此类表示用来发送和接收数据报包的套接字
ds = new DatagramSocket();
/*
B:创建数据并把数据打包
void send(DatagramPacket p)
从此套接字发送数据报包。DatagramPacket 包含的信息指示:将要
发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号
DatagramPacket 此类表示数据报包
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
*/
//创建数据
byte[] bys = "Hello,World!".getBytes();
//长度
int length = bys.length;
//IP地址对象
InetAddress address = InetAddress.getByName("127.0.0.1");
//端口
int port = 10086;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
// C:通过调用Socket对象的发送方法,发送数据包
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
} finally {
// D:释放资源
ds.close();
}
}
@Test
public void receive() {
DatagramSocket ds = null;
try {
// A:创建接收端Socket对象
// DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口
ds = new DatagramSocket(10086);
// B:创建一个数据包(接收容器)
// DatagramPacket(byte[] buf, int length) 构造
// DatagramPacket,用来接收长度为 length 的数据包
byte[] bys = new byte[1024];
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);
// C:调用Socket对象的接收方法接收数据
// void receive(DatagramPacket p) 从此套接字接收数据报包
// <此方法在接收到数据报前一直阻塞>
ds.receive(dp); // 阻塞式
// D:解析数据包,并显示在控制台
// 获取对方的 IP
//public InetAddress getAddress() 返回某台机器的 IP 地址
// ,此数据报将要发往该机器或者是从该机器接收到的
InetAddress address = dp.getAddress();
String ip = address.getHostAddress();
// public byte[] getData() 返回数据缓冲区。
// public int getLength() 返回将要发送或接收到的数据的长度
byte[] bys2 = dp.getData();
int len = dp.getLength();
String s = new String(bys2,0,len);
System.out.println(ip+"传递的数据是:"+s);
} catch (IOException e) {
e.printStackTrace();
} finally {
// E:释放资源
ds.close();
}
}
<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
为了表示URL,java.net 中实现了类 URL。我们可以通过下面的构造器来初始化一个 URL 对象,URL类的构造器都声明抛出非运行时异常,必须要对这一异常进行处理,通常是用 try-catch 语句进行捕获。
public URL (String spec)
:通过一个表示 URL 地址的字符串可以构造一个URL对象public URL(URL context, String spec)
:通过基 URL 和相对 URL 构造一个 URL 对象public URL(String protocol, String host, String file)
public URL(String protocol, String host, int port, String file)
一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:
public String getProtocol()
获取该 URL 的协议名public String getHost()
获取该 URL 的主机名public String getPort()
获取该 URL 的端口号public String getPath()
获取该 URL 的文件路径public String getFile()
获取该 URL 的文件名public String getQuery()
获取该 URL 的查询名针对 HTTP 协议的 URLConnection 类:
openStream()
:能从网络上读取数据openConnection()
生成对应的 URLConnection对象。如果连接过程失败,将产生IOExceptionpublic Object getContent() throws IOException
public int getContentLength()
public String getContentType()
public long getDate()
public long getLastModified()
public InputStream getInputStream() throws IOException
public OutputSteram getOutputStream() throws IOException
类 URL 和 URLConnection 提供了最高级网络应用。URL 的网络资源的位置来同一表示 Internet 上各种网络资源。通过URL对象可以创建当前应用程序和 URL 表示的网络资源之间的连接,这样当前程序就可以读取网络资源数据,或者把自己的数据传送到网络上去。
public static void main(String[] args) {
HttpURLConnection urlConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL("http://localhost:8080/examples/tree.jpg");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
is = urlConnection.getInputStream();
fos = new FileOutputStream("net\\tree.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("下载完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(urlConnection != null){
urlConnection.disconnect();
}
}
}
原文:https://www.cnblogs.com/liujiaqi1101/p/13340690.html