1.在KYLIN上装APACHE2.2需将EnableSendfile设置为off
2.MappedByteBuffer VS FileChannel å°å¼ºå°å¼±ï¼
3.java中如何实现从客户端发送文件到服务器端?
4.这是源码一份很全很全的IO基础知识与概念
5.零拷贝技术及在Java中应用
在KYLIN上装APACHE2.2需将EnableSendfile设置为off
装好apache2.2后会出现不能传输html页面,但是源码默认却能显示It Works 主要原因是这个指令控制m = null;
/**建立socekt通信,等待服务器进行连接*/
try {
ss = new ServerSocket();
s = ss.accept();
} catch (IOException e) {
e.printStackTrace();
}
/**读取一行客户端发送过来的源码约定信息*/
try {
InputStreamReader isr = new InputStreamReader(s.getInputStream());
BufferedReader br = new BufferedReader(isr);
comm = br.readLine();
} catch (IOException e) {
System.out.println("服务器与客户端断开连接");
}
/**开始解析客户端发送过来的请求命令*/
int index = comm.indexOf("/#");
/**判断协议是否为发送文件的协议*/
String xieyi = comm.substring(0, index);
if(!xieyi.equals("")){
System.out.println("服务器收到的协议码不正确");
return;
}
/**解析出文件的名字和大小*/
comm = comm.substring(index + 2);
index = comm.indexOf("/#");
String filename = comm.substring(0, index).trim();
String filesize = comm.substring(index + 2).trim();
/**创建空文件,用来进行接收文件*/
file = new File(filename);
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("服务器端创建文件失败");
}
}else{
/**在此也可以询问是源码否覆盖*/
System.out.println("本路径已存在相同文件,进行覆盖");
}
/**以上就是源码客户端代码中写到的服务器的准备部分*/
/
*** 服务器接收文件的关键代码*/
try {
/**将文件包装到文件输出流对象中*/
fos = new FileOutputStream(file);
long file_size = Long.parseLong(filesize);
is = s.getInputStream();
/**size为每次接收数据包的长度*/
int size = 0;
/**count用来记录已接收到文件的长度*/
long count = 0;
/**使用while循环接收数据包*/
while(count < file_size){
/**从输入流中读取一个数据包*/
size = is.read(buffer);
/**将刚刚读取的数据包写到本地文件中去*/
fos.write(buffer, 0, size);
fos.flush();
/**将已接收到文件的长度+size*/
count += size;
System.out.println("服务器端接收到数据包,大小为" + size);
}
} catch (FileNotFoundException e) {
System.out.println("服务器写文件失败");
} catch (IOException e) {
System.out.println("服务器:客户端断开连接");
}finally{
/
*** 将打开的源码爱源码视频文件关闭
* 如有需要,也可以在此关闭socket连接
* */
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}//catch (IOException e)
}//finally
}//public static void main(String[] args)
}//public class ServerReceive
客户端源码:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
/
***
* 文件名:ClientSend.java
* 实现功能:作为客户端向服务器发送一个文件
*
* 具体实现过程:
* 1、源码建立与服务器端的源码连接,IP:.0.0.1,源码 port:
* 2、源码将文件的源码名字和大小通过自定义的文件传输协议,发送到服务器
* 3、源码循环读取本地文件,源码将文件打包发送到数据输出流中
* 4、源码关闭文件,源码结束传输
*
* */
public class ClientSend {
public static void main(String[] args) {
/**与服务器建立连接的通信句柄*/
Socket s = null;
/**定义文件对象,即为要发送的文件
* 如果使用绝对路径,不要忘记使用'/'和'\'的区别
* 具体区别,请读者自行查询
* */
File sendfile = new File("API.CHM");
/**定义文件输入流,音效处理 源码用来打开、读取即将要发送的文件*/
FileInputStream fis = null;
/**定义byte数组来作为数据包的存储数据包*/
byte[] buffer = new byte[ * 5];
/**定义输出流,使用socket的outputStream对数据包进行输出*/
OutputStream os = null;
/**检查要发送的文件是否存在*/
if(!sendfile.exists()){
System.out.println("客户端:要发送的文件不存在");
return;
}
/**与服务器建立连接*/
try {
s = new Socket(".0.0.1", );
}catch (IOException e) {
System.out.println("未连接到服务器");
}
/**用文件对象初始化fis对象
* 以便于可以提取出文件的大小
* */
try {
fis = new FileInputStream(sendfile);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
/**首先先向服务器发送关于文件的信息,以便于服务器进行接收的相关准备工作
* 具体的准备工作,请查看服务器代码。
*
* 发送的内容包括:发送文件协议码(此处为)/#文件名(带后缀名)/#文件大小
* */
try {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("/#" + sendfile.getName() + "/#" + fis.available());
ps.flush();
} catch (IOException e) {
System.out.println("服务器连接中断");
}
/
*** 此处睡眠2s,等待服务器把相关的工作准备好
* 也是为了保证网络的延迟
* 读者可自行选择添加此代码
* */
try {
Thread.sleep();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
/**之前的准备工作结束之后
* 下面就是文件传输的关键代码
* */
try {
/**获取socket的OutputStream,以便向其中写入数据包*/
os = s.getOutputStream();
/** size 用来记录每次读取文件的大小*/
int size = 0;
/**使用while循环读取文件,直到文件读取结束*/
while((size = fis.read(buffer)) != -1){
System.out.println("客户端发送数据包,大小为" + size);
/**向输出流中写入刚刚读到的数据包*/
os.write(buffer, 0, size);
/**刷新一下*/
os.flush();
}
} catch (FileNotFoundException e) {
System.out.println("客户端读取文件出错");
} catch (IOException e) {
System.out.println("客户端输出文件出错");
}finally{
/
*** 将打开的文件关闭
* 如有需要,也可以在此关闭socket连接
* */
try {
if(fis != null)
fis.close();
} catch (IOException e) {
System.out.println("客户端文件关闭出错");
}//catch (IOException e)
}//finally
}//public static void main(String[] args)
}//public class ClientSend
这是一份很全很全的IO基础知识与概念
在操作系统的核心领域,输入/输出(IO)扮演着至关重要的角色,它主要分为磁盘IO和网络IO两个模块,两者在用户空间和内核空间之间穿梭,确保数据传输的高效与稳定。让我们深入探讨一下这两个关键概念。 首先,IO操作涉及数据在用户空间和内核空间之间的word插入源码传输,这种切换往往伴随着数据拷贝。读取操作中,内核会检查缓冲区,可能直接读取数据,或者在数据未就绪时等待。相比之下,写入操作则从用户空间拷贝数据到内核空间,由操作系统决定何时执行磁盘或网络写入。这种内核与用户空间的隔离,是系统稳定性的基石。 代码示例生动地展示了这种切换:在用户空间执行的赋值操作,一旦涉及到文件写入,就会切换到内核空间。系统调用(如写文件)、异常处理(如缺页)和设备中断是用户态转内核态的常见途径。通过命令行工具top,我们可以实时监控CPU的使用情况,理解任务的绝佳买点源码运行状态。 CPU时间分配方面,理想状态是大部分时间处于空闲(idle),而用户空间和内核空间的运行时间则相对较少。例如,7.%的CPU用于用户空间处理,7.0%用于内核空间,其余大部分时间则在等待任务。 在数据传输方式上,PIO和DMA各有利弊。PIO需要CPU频繁介入,效率相对较低,而DMA则允许CPU在数据传输时处理其他任务,降低了CPU的负担。DMA的工作流程包括用户进程请求、操作系统调度、DMA读取数据至内核缓冲区,最后由CPU将数据复制到用户空间。 在数据复制的51破解源码过程中,DMA负责内核缓冲区到磁盘或网络设备的传输,而用户空间与内核空间之间的操作则主要由CPU处理。尽管PIO模式在现代系统中已不太常见,理解这些细节对于优化IO性能至关重要。 缓冲IO和直接IO是两种常见的数据传输策略。缓冲IO通过在内核和用户空间之间设置缓冲区,提升性能,但会增加CPU和内存消耗。而直接IO则跳过内核缓冲,减少数据拷贝,但可能影响性能,尤其在数据不在缓存时。零拷贝IO技术则试图在两者之间找到平衡,减少不必要的拷贝和进程切换,显著提高效率。 在实际应用中,Apache和Kafka等工具采用零拷贝技术,如sendfile()接口,通过文件描述符和socket操作,实现高效的数据传输。同时,理解同步/异步和阻塞/非阻塞的概念也对网络编程至关重要。同步操作会阻塞等待结果,而非阻塞则会立即返回,如看病和看手机的场景。异步操作允许任务并行进行,提升系统响应速度。 总的来说,掌握IO操作、其背后的原理以及同步/异步、阻塞/非阻塞的概念,是构建高效网络服务的基础。深入研究操作系统对IO的优化策略,将有助于我们理解高性能服务器的运作机制。如果你对此领域感兴趣,可以参考以下文章来进一步深化理解: 嵌入式开发进阶:腾讯首发Linux内核源码 嵌入式转内核开发经验分享 通过这些资源,你将能够更好地把握IO操作的精髓,为你的编程实践增添更强的实战能力。零拷贝技术及在Java中应用
零拷贝技术及在Java中的应用
前言
本文旨在探讨零拷贝技术在Java领域中的应用,通过对几个知名开源软件的源码分析,以揭示其背后的优化机制。零拷贝技术的核心在于减少数据在用户空间与内核空间之间不必要的复制,从而提升性能。
什么是零拷贝
零拷贝技术是指在数据传输过程中,无需CPU参与数据从一个内存区域复制到另一个内存区域的过程,以减少系统开销。
OS层传统I/O
在Linux环境下,传统I/O操作涉及到数据从用户空间到内核空间,以及从内核空间到磁盘或网络设备的复制,通常需要两次系统调用,产生四次上下文切换。
零拷贝技术mmap
通过mmap系统调用,Linux将内核空间与用户空间的虚拟地址映射到同一物理地址,实现数据在内核空间中的直接操作,从而减少CPU和内存之间的数据复制。mmap结合write操作能显著提升I/O速度,同时减少上下文切换。
sendfile
sendfile是Linux内核提供的另一个系统调用,允许在文件描述符之间传输数据,避免了内核缓冲区与用户缓冲区之间的数据复制,进一步实现了零拷贝。其流程包括三次数据拷贝,其中两次是DMA拷贝。
sendfile+DMA scatter/gather
通过在内核空间和socket buffer之间记录内存地址和偏移量,sendfile操作可以进一步减少CPU拷贝,实现更高效的零拷贝。scatter/gather方法减少了数据在内核空间和socket之间的拷贝,但硬件及驱动程序的支持是关键。
splice
splice调用引入于Linux 2.6.版本,具备了sendfile的所有功能,并且提供了更广泛的用例。它能够替代sendfile机制,实现更灵活的数据传输。
小结
零拷贝技术通过减少CPU拷贝和上下文切换,显著提升了数据传输效率。尽管两次DMA拷贝仍难以避免,但这些技术在不同层面上优化了数据传输过程。
Java层零拷贝技术
考虑到JVM的垃圾回收机制,Java的零拷贝技术主要关注如何利用堆外内存减少内存的移动。DirectByteBuffer提供了直接与操作系统内存交互的接口,避免了JVM堆内存与OS用户堆之间的数据拷贝。
Netty与零拷贝
Netty通过优化数据传输流程,实现了高效的零拷贝技术,减少了不必要的数据拷贝,从而提升整体性能。
开源分析Tomcat
Tomcat通过利用零拷贝技术,如sendfile,来优化静态资源的传输,避免不必要的数据压缩过程,以提升性能和带宽利用率。
RocketMQ与零拷贝
RocketMQ通过使用mmap技术实现高效的CommitLog文件传输,减少了JVM堆内存的拷贝,从而提高了消息处理速度。
结语
本文综述了零拷贝技术的原理及其在Java领域中的应用,通过分析开源软件的源码,展示了零拷贝技术的实践与优势。希望本文能为读者提供启发,引导在实际开发中更有效地利用零拷贝技术,提升系统性能。