1.InetAddress
通过String获取InetAddress
netAddress.getByName(“127.0.0.1”);
InetAddress.getByName(“localhost”);
InetAddress.getLocalHost();
通过InetAddress获取相关信息
InetAddress byName ;
System.out.println(byName);//获取域名+ip地址
System.out.println(byName.getAddress());//获取二进制的ip地址
System.out.println(byName.getCanonicalHostName());//获取String类型的ip地址
System.out.println(byName.getHostAddress());//获取主机ip地址
System.out.println(byName.getHostName());//获取主机域名
2.InetSocketAddress
InetSocketAddress中有private访问权限的hostname,addr(InetAddress类型的变量)和port 三个元素,也就是它和我们之前讲过的InetAddress是组合关系。
绑定套接字地址
InetSocketAddress inetSocketAddress = new InetSocketAddress(“127.0.0.1”, 8080);
输出套接字地址信息
System.out.println(inetSocketAddress.getAddress());
System.out.println(inetSocketAddress.getHostName());
System.out.println(inetSocketAddress.getPort());
3.Socket
3.1、Socket介绍
1、利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实 上的标准。
2、网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。即socket = new Socket(serverIp, port);
3、通信的两端都要有Socket,是两台机器间通信的端点。
4、网络通信其实就是Socket间的通信。
5、Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
6、一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。
7、Socket分类:
1). 流套接字(stream socket):使用TCP提供可依赖的字节流服务
2). 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
3.2 流套接字
服务端:
1.调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。
2.调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。
3.调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。
4.关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
package lesson02;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
//客户端
public class TcpClientDemo01 {
public static void main(String[] args) {
Socket socket = null;
OutputStream outputStream = null;
try {
//要知道服务端的地址
InetAddress serverIp = InetAddress.getByName("127.0.0.1");
//端口号
int port = 9998;
//创建一个socket连接
socket = new Socket(serverIp, port);
//发送IO流
outputStream = socket.getOutputStream();
outputStream.write("19195216 HongZhiHao".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
1.创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务端的通信路线。若连接失败,则会出现异常。
2.打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
3.按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入路线的信息),通过输出流将信息写入线程
4.关闭 Socket:断开客户端到服务器的连接,释放线路
package lesson02;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream inputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
//要有一个地址
serverSocket = new ServerSocket(9998);
//while (true) {
//等待客户端连接过来
socket = serverSocket.accept();
//读取客户端的消息
inputStream = socket.getInputStream();
//管道流
byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
//这边也可以构建一个大小为socket.available的byte数组,socket.available是待接收的byte长度,后面就不需要再while循环了,但是空间消耗会比较大
int len;
while ((len = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
//这个地方要注意最后一次写入时,byte数组不一定会被占满,所以会写入很多无意义的空格,读取的时候要考虑使用trim()来消除无用的空格
System.out.println(byteArrayOutputStream.toString());
//}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (byteArrayOutputStream != null) {
byteArrayOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
补充1:文件传输
传输文件的话,在客户端内,要文件用流的方式输入到输出流里,再让输出流输出到服务端内。这里用到了一个流过滤器的组合使用,因为文件只能通过文件过滤器来进行传输,但单纯的流的传输用buffer缓冲会快很多,所以将它们组合起来。
bis = new BufferedInputStream(new FileInputStream(new File("me.jpg")));
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer)) != -1){
writer.write(buffer,0,len);
}
然后在客户端,需要将得到的输入流,再通过流的方式解析成文件。这里也用到了一个流过滤器的组合使用。
BufferedOutputStream reader = new BufferedOutputStream(new FileOutputStream(new File("new_me.jpg")));
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
reader.write(buffer,0,len);
}
补充2:优雅的半关闭
socket.shutdownOutput();
socket.shutdownInput();
就是当某个端既需要输入流也需要输出流的时候,
为了避免输出流输入到自己的输入流里,可以在输入流结束后,关闭输入流,输出流结束后再关闭输出流,不然的话,程序可能会一直停住(因为另一端可能有accept()这种阻断接受)
3.3 数据报套接字
udp特性:
1.将数据、源、目的封装成数据包,不需要建立连接
2.每个数据报的大小限制在64K内
3.发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
5.可以广播发送
6.发送数据结束时无需释放资源,开销小,速度快
Java udp:
1、类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。
2、UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
3、DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
4、UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。
接收端
package lesson03;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpServerDemo01 {
public static void main(String[] args) throws Exception{
//开放端口
DatagramSocket socket = new DatagramSocket(9090);
//接受数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//阻塞接受
socket.receive(packet);
System.out.println(new String(packet.getData()));
//关闭连接
socket.close();
}
}
发送端
package lesson03;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpClientDemo01 {
public static void main(String[] args) throws Exception {
//1.建立一个socket
DatagramSocket socket = new DatagramSocket();
//2.建个包
String msg = "helloWorld";
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
//数据,发给谁,发什么
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length,localhost,port);
//3.发送包
socket.send(packet);
//4.关闭流
socket.close();
}
}
4.总结与补充
学好java网络编程,首先得了解套接字和tcp、udp等计算机网络的概念,并且对io流要足够的熟悉,因为网络编程的本质就是流的传输。网络编程方面可以考虑使用Java7引进的try-with-resources的语法糖,来避免写大量的关闭流代码。