Java之网络编程
InetAddress
DatagramPacket、DatagramSocket
ServerSocket、Socket
SocketAddress -> InetSocketAddress
1. InetAddress
jdk手册中发现没有构造方法,说明构造方法是私有的,也就是说我们只能用它的static静态方法去获取InetAddress的对象,再使用非静态方法
常用方法:
静态:
static InetAddress getLocalHost() //能够返回当前主机InetAddress类的对象
static InetAddress getByName(String host) //返回指定主机名的InetAddress类的对象
非静态:
String getHostName() //获取主机名
String getHostAddress() //获取主机IP地址
获取本机IP地址和主机名 获取指定主机名的IP地址和主机名2. UDP协议收发数据
DatagramPacket:包装原始数据为socket数据包
DatagramSocket:发送包装好的socket数据包
2.1. UDP发送端
流程:
udp发送端创建DatagramPacket对象,封装数据,接收的ip和port(在构造方法中传所有参数)
创建DatagramSocket
调用DatagramSocket类的方法send,发送数据包
关闭资源DatagramSocket类
2.2. UDP接收端
流程:
udp接收端创建DatagramSocket,bind port,收发port要相同
闯进byte数组,接收发送端发送过来的数据包
创建数据包对象DatagramPacket
调用DatagramSocket对象的阻塞接收方法receive()
拆包,能够获取到发送过来包的length、IP地址、数据。
关闭资源
3. TCP协议收发数据
3.1. 简单的TCP客户端、服务器端
先运行服务器端,等待客户端连接,再运行client
client向server发送消息,server收到后再回给client消息
客户端代码 服务器端代码服务器端的核心在于,通过accept拿到客户端的连接Socket,进而获得读取数据的InputStream对象和写数据的OutputStream对象
3.2. TCP实现文件上传
先运行服务器端,再等待客户端连接
客户端代码 服务器端代码运行后发现,server和client都卡住了,主要是服务器端卡在while((len = is.read(b)) != -1)这里,一直阻塞
原因是,服务器端并不知道client传输过来的数据包什么时候结束,因此需要修改客户端,告知服务器端什么时候该停止接收数据
Socket中有一个方法:public void shutdownOutput()
这个方法就是客户端用于告知服务器端,我的OutputStream在什么点应该结束,这个是方法中自己定一个一个结束标识符,不用关心是什么,只要调用它,服务器端就知道什么点该退出阻塞read了。
修改后的client端代码3.3. 大文件多线程上传
这里做一个对比,如果用单线程上例传输一个1G的大文件,经过反复测试,耗时大约17~18s
现在改为用多线程传输:
有空再做
3.4. Socket远程调用示例
这个demo可以在服务器端接收客户端的数据,并用反射或者动态代理来完成远程过程调用
反射和动态代理见:https://www.jianshu.com/p/0d0c13b92e04
代码:
程序结构public class ServerRunnable implements Runnable{
Socket socket = null;
InputStream in = null;
OutputStream out = null;
public ServerRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String param = br.readLine();
/**
* this place can be using reflect to do something
*/
GetDataServiceImpl getDataServiceImpl = new GetDataServiceImpl();
String result = getDataServiceImpl.getData(param);
out = socket.getOutputStream();
PrintWriter pw = new PrintWriter(out);
pw.println(result);
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
in.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}