⑴ c语言中buffer到底是什么意思是数组缓冲区为什么一般C程序中都不定义他直接拿来用呢
Buffer是NodeJS的重要数据类型,很有广泛的应用。代表原始堆的分配额的数据类型。在NodeJS中以类数组的方式使用。
在Buffer类的描述中,Buffer被定义为用于特定基本类型数据的容器,且是特定基本类型的线性优先元素序列。
Buffer提供了一个字节缓冲区,它可以从channels中读取数据到Buffer,也可以将Buffer中的数据写入到channels,所以NIO被定义为面向缓冲区编程,而IO则是被定义为面向流的编程。
当一个缓存中的数据被多次读取,实际上就减少了该数据从慢速设备中读取的量,这就存在某种算法去选择什么数据需要保存在cache中,因为尽可能多的让cache命中能提高性能。
(1)c语言nio什么意思扩展阅读
Buffer类的四个变量
1、capacity
容量,必须初始化的值(因为底层是数组)
2、limit
上界,缓冲区的临界区,即最多可读到哪个位置
3、position
下标,当前读取到的位置(例如当前读出第5个元素,则读完后,position为6)
4、mark
标记,备忘位置
⑵ 什么是nio模式
Java NIO与IO的区别和比较
参考网络文档:http://wenku..com/view/b038a60590c69ec3d5bb7580.html
下载不需要财富
⑶ NIO和TIJ是什么
JDK 1.4版本(包括之后的版本)最显着的新特性就是增加了NIO(New IO),能够以非阻塞的方式处理网络的请求,这就使得在Java中只需要少量的线程就能处理大量的并发请求了。但是使用NIO不是一件简单的技术,它的一些特点使得编程的模型比原来阻塞的方式更为复杂。
在JDK 1.4的新特性中,NIO无疑是最显着和鼓舞人心的。NIO的出现事实上意味着Java虚拟机的性能比以前的版本有了较大的飞跃。在以前的JVM的版本中,代码的执行效率不高(在最原始的版本中Java是解释执行的语言),用Java编写的应用程序通常所消耗的主要资源就是CPU,也就是说应用系统的瓶颈是CPU的计算和运行能力。在不断更新的Java虚拟机版本中,通过动态编译技术使得Java代码执行的效率得到大幅度提高,几乎和操作系统的本地语言(例如C/C++)的程序不相上下。在这种情况下,应用系统的性能瓶颈就从CPU转移到IO操作了。尤其是服务器端的应用,大量的网络IO和磁盘IO的操作,使得IO数据等待的延迟成为影响性能的主要因素。NIO的出现使得Java应用程序能够更加紧密地结合操作系统,更加充分地利用操作系统的高级特性,获得高性能的IO操作。
JIT Compiler(Just-in-time Compiler) 即时编译 最早的Java建置方案是由一套转译程式(interpreter),将每个Java指令都转译成对等的微处理器指令,并根据转译后的指令先后次序依序执行,由于一个Java指令可能被转译成十几或数十几个对等的微处理器指令,这种模式执行的速度相当缓慢。 针对这个问题,业界首先开发出JIT(just in time)编译器。当Java执行runtime环境时,每遇到一个新的类别(class:类别是Java程式中的功能群组),类别是Java程式中的功能群组-JIT编译器在此时就会针对这个类别进行编译(compile)作业。经过编译后的程式,被优化成相当精简的原生型指令码(native code),这种程式的执行速度相当快。花费少许的编译时间来节省稍后相当长的执行时间,JIT这种设计的确增加不少效率,但是它并未达到最顶尖的效能,因为某些极少执行到的Java指令在编译时所额外花费的时间可能比转译器在执行时的时间还长,针对这些指令而言,整体花费的时间并没有减少。 基于对JIT的经验,业界发展出动态编译器(dynamic compiler),动态编译器仅针对较常被执行的程式码进行编译,其余部分仍使用转译程式来执行。也就是说,动态编译器会研判是否要编译每个类别。动态编译器拥有两项利器:一是转译器,另一则是JIT,它透过智慧机制针对每个类别进行分析,然后决定使用这两种利器的哪一种来达到最佳化的效果。动态编译器针对程式的特性或者是让程式执行几个循环,再根据结果决定是否编译这段程式码。这个决定不见得绝对正确,但从统计数字来看,这个判断的机制正确的机会相当高。事实上,动态编译器会根据“历史资料”做决策,所以程式执行的时间愈长,判断正确的机率就愈高。以整个结果来看,动态编译器产生的程式码执行的速度超越以前的JIT技术,平均速度可提高至50%。
⑷ C语言 阻塞,非阻塞和多线程有什么关系
阻塞是在传统的网络编程中我们依赖于ServerSocket,Socket进行通信,大致的框架就是ServerSocket调用accept方法,等待客户端的连接,如果连接进来的时候则创建一个服务器端socket,客户端和服务器端socket建立好InputStream 和outputStream通道进行通信,在这个网络IO的过程中inputStream的read 和outputStream的write方法都可能发送阻塞。为了减少这种阻塞对其他连接的影响,一般都会在服务器端为每个连接开辟一个新的线程,或者使用线程池技术来避免线程的创建销毁同时又一定程度支持并发量。然而这种情况下,如果发生大量的read 或者write阻塞线程池的效率会大大降低,而且操作系统也额外需要频繁的处理cpu的切换。
非阻塞式通信实际是对上述模式的扩展,它的核心思想是为传统的socket加入事件监听的功能,操作系统可以在socket和serversocket上进行事件监听,一旦监听的对象发生了连接和可读可写的事件,监听器就会对注册了事件的对象返回相应的通知。在javaNIO中实现这一套的机制就是把socket 和ServerSocket重写成为SocketChanel,ServerSocketChanel,他们的底层仍然使用socket实现,所以原则上javaNIO包可以完全实现阻塞和非阻塞两种编程模式。事件监听的功能由Selection类完成,他使用select方法一直阻塞式监听注册了的事件是否发生,对于每一个发生的事件,他都会返回一个selectionKey,通过这个key我们就可以确定这个事件的发生源(socket)和相关信息。对于ServerSocketChanel,Socketchanel分别对应了不同的事件,serverChanel只有OP_ACCEPT代表是否可以接受连接,而socketChanel则有OP_CONNECT、read、write事件。笔者认为与阻塞IO相比他的优势在于可以避免read 和write的阻塞,因为这个比较具有实际意义的。比如是一个网络文件传输系统,read方法可能会因为网络原因发生多次阻塞,使用非阻塞IO read的话线程可以立即返回去处理其他任务。
多线程是在进程中进一步去划分的独立单元。
⑸ 用Nio技术实现c/s结构程序
服务端程序:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
public static final int SERVERPORT=5555;
public static final String[] USERNAME={"1","2","3","4","5","jack","tom"};
public static final String PASSWORD="1";
public static final String ISACK="ACK";
public static final String ISNAK="NAK!";
// Selector selector;//选择器
// SelectionKey key;//key。 一个key代表一个Selector 在NIO通道上的注册,类似主键;
// //取得这个Key后就可以对Selector在通道上进行操作
private ByteBuffer echoBuffer = ByteBuffer.allocate( 1024 );// 通道数据缓冲区
public NioServer(){
}
public static void main(String[] args) throws IOException {
NioServer ns=new NioServer();
ns.BuildNioServer();
}
public void BuildNioServer() throws IOException{
/////////////////////////////////////////////////////////
///////先对服务端的ServerSocket进行注册,注册到Selector ////
/////////////////////////////////////////////////////////
ServerSocketChannel ssc = ServerSocketChannel.open();//新建NIO通道
ssc.configureBlocking( false );//使通道为非阻塞
ServerSocket ss = ssc.socket();//创建基于NIO通道的socket连接
//新建socket通道的端口
ss.bind(new InetSocketAddress("127.0.0.1",SERVERPORT));
Selector selector=Selector.open();//获取一个选择器
//将NIO通道选绑定到择器,当然绑定后分配的主键为skey
//SelectionKey skey =
ssc.register( selector, SelectionKey.OP_ACCEPT );
////////////////////////////////////////////////////////////////////
//// 接收客户端的连接Socket,并将此Socket也接连注册到Selector ////
///////////////////////////////////////////////////////////////////
while(true){
int num = selector.select();//获取通道内是否有选择器的关心事件
if(num<1){continue; }
Set selectedKeys = selector.selectedKeys();//获取通道内关心事件的集合
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {//遍历每个事件
try{
SelectionKey key = (SelectionKey)it.next();
//有一个新联接接入事件,服务端事件
if ((key.readyOps() & SelectionKey.OP_ACCEPT)
== SelectionKey.OP_ACCEPT) {
// 接收这个新连接
ServerSocketChannel serverChanel = (ServerSocketChannel)key.channel();
//从serverSocketChannel中创建出与客户端的连接socketChannel
SocketChannel sc = serverChanel.accept();
sc.configureBlocking( false );
// Add the new connection to the selector
// 把新连接注册到选择器
//SelectionKey newKey =
sc.register( selector, SelectionKey.OP_READ );
it.remove();
System.out.println( "Got connection from "+sc );
}else
//读客户端数据的事件,此时有客户端发数据过来,客户端事件
if((key.readyOps() & SelectionKey.OP_READ)
== SelectionKey.OP_READ){
// 读取数据
SocketChannel sc = (SocketChannel)key.channel();
while(sc.read(echoBuffer)> 0){ ;}
echoBuffer.flip();
byte [] content = new byte[echoBuffer.limit()];
echoBuffer.get(content);
String result=new String(content);
doPost(result,sc);
echoBuffer.clear();
it.remove();
}
}catch(Exception e){}
}
}
}
Hashtable table=new Hashtable();
public void doPost(String str,SocketChannel sc){
boolean isok=false;
int index=str.indexOf('|');
if(index>=0){ //index>0 有"|"符号,代表登陆,没有表示普通聊天
String name=str.substring(0,index);
String pswd=str.substring(index+1);
if(pswd==null){pswd="";}
if(name!=null){
if(pswd.equals(PASSWORD) ){
isok=false;
for(int i=0;i<USERNAME.length;i++){
if(USERNAME[i].equals(name)){
isok=true;
break;
}
}
}else{
isok=false;
}
}else{
isok=false;
}
String result="";
if(isok){
result="ACK";
//加入到用户通道列表中
User user=new User();
user.password=pswd;
user.name=name;
user.sc=sc;
table.put(user.name, user);
}else{
result="NAK!";
}
ByteBuffer bb = ByteBuffer.allocate( result.length() );
bb.put(result.getBytes());
bb.flip();
try {
sc.write(bb);
} catch (IOException e) {
e.printStackTrace();
}
bb.clear();
}else{ //普通聊天
//遍历所有己注册通道,向所有人发消息(包括发送者自己)
System.out.println("通道数:"+table.size());
Enumeration en=table.elements();
while(en.hasMoreElements()){
User user=(User)en.nextElement();
SocketChannel channel=user.sc;
if(user!=null && channel!=null && channel.isConnected()){
System.out.println("发送:str"+str);
ByteBuffer bb = ByteBuffer.allocate( str.length() );
bb.put(str.getBytes());
bb.flip();
try {
channel.write(bb);
} catch (IOException e) {
e.printStackTrace();
}
bb.clear();
}else{
if(user!=null && user.name!=null){
table.remove(user.name);
}
}
}
}
}
public class User{
public String name="";
public String password="";
public boolean isLogin=false;
public SocketChannel sc=null;
}
}
客户端:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class UserClient implements ActionListener{
JFrame jf;
JPanel jp;
JLabel label_name;
JLabel label_pswd;
JTextField userName;
JButton jb;
JPasswordField paswrd;
JLabel hintStr;
public UserClient (){
jf=new JFrame("XXX 登陆系统");
jp=new JPanel();
jf.setContentPane(jp);
jf.setPreferredSize(new Dimension(350,220));
jp.setPreferredSize(new Dimension(350,220));
jp.setBackground(Color.gray);
label_name=new JLabel();
label_name.setPreferredSize(new Dimension(150,30));
label_name.setText("请输入帐户(数字或英文):");
userName=new JTextField();
userName.setPreferredSize(new Dimension(150,30));
jp.add(label_name);
jp.add(userName);
label_pswd=new JLabel();
label_pswd.setPreferredSize(new Dimension(150,30));
label_pswd.setText("请输入密码:");
jp.add(label_pswd);
paswrd=new JPasswordField();
paswrd.setPreferredSize(new Dimension(150,30));
jp.add(paswrd);
jb=new JButton("OK");
jb.setPreferredSize(new Dimension(150,30));
jb.setText("确 定");
jb.addActionListener( this);
jp.add(jb);
hintStr=new JLabel();
hintStr.setPreferredSize(new Dimension(210,40));
hintStr.setText("");
hintStr.setForeground(Color.RED);
jp.add(hintStr);
jf.pack();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private String name;
private String pswd;
public void actionPerformed(ActionEvent e) {
if(e.getSource()==jb){
name=userName.getText().trim();
pswd=new String(paswrd.getPassword());
if(pswd==null){
pswd="";
}else{
pswd=pswd.trim();
}
if(name!=null && name.length()>0){
hintStr.setText("正在验证客户端,请稍候...");
start();
}
}else
if(e.getSource()==clear){//清屏
text.setText("");
}else
if(e.getSource()==send){//发送
String msg=this.jtf.getText();
if(msg!=null){
if(msg.trim().length()>0){
msg=" "+name+" said:"+msg+"\r\n";
sendMessage(msg);
jtf.setText("");
}
}
}
}
OutputStream os;
Socket s;
InputStream is;
public void start(){
//建立联网线程
new Thread(new Runnable(){
public void run() {
try {
s=new Socket("127.0.0.1",5555);
//写
os=s.getOutputStream();
os.write(name.getBytes());
os.write('|');//用户名与密码用"|"分隔
os.write(pswd.getBytes());
os.flush();
//读内容
Thread.sleep(1000);
is=s.getInputStream();
int len=is.available();
System.out.println("len:"+len);
byte[] bytes=new byte[len];
is.read(bytes);
String resut=new String(bytes);
System.out.println("resut:"+resut);
if(resut.equals("ACK")){
hintStr.setText("验证成功,欢迎光临!");
//TODO 这里通过返回结果处理
handleLoginResult();
}else{
paswrd.setText(null);
hintStr.setText("用户名或密码错误,请重新输入");
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
}
}
}).start();
}
////////////////////////////////////////////////////////////////////
//处理登陆结果,出新界面
//登陆后新界面的元素组件定义在这里,注意,
//现在随便弄的,你要改漂亮些
////////////////////////////////////////////////////////////////////
JTextArea text;
JButton send;
JButton clear;
JTextArea jtf;
public void handleLoginResult(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.jp.removeAll();//清空所有组件;
jf.setSize(800,600);
jp.setSize(800,600);
jf.setPreferredSize(new Dimension(800,600));
jp.setPreferredSize(new Dimension(800,600));
//加聊天内容框
text=new JTextArea();
text.setBackground(Color.WHITE);
text.setForeground(Color.BLUE);
text.setPreferredSize(new Dimension(750,450));
jp.add(text);
//加发送内容框
jtf=new JTextArea();
jtf.setPreferredSize(new Dimension(750,50));
jp.add(jtf);
//加按钮
send=new JButton("发送");
clear=new JButton("清屏");
send.setPreferredSize(new Dimension(100,30));
clear.setPreferredSize(new Dimension(100,30));
jp.add(send);
jp.add(clear);
send.addActionListener(this);
clear.addActionListener(this);
jf.pack();
jf.repaint();
//开始读线程
readMessage();
}
//////////////////////////////////////////////////////
//发送消息线程
//////////////////////////////////////////////////////
public void sendMessage(String msg){
final String toSend=msg;
new Thread(
new Runnable(){
public void run(){
if(s==null ){
return;
}
//写
try {
System.out.println("发送:"+toSend);
os.write(toSend.getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
).start();
}
/////////////////////////////////////////////////////////
//读取线程,死循环,不停读取
public boolean isRunning=true;
public void readMessage( ){
new Thread(
new Runnable(){
public void run(){
while(isRunning){
if(s==null ){
return;
}
try {
InputStream is=s.getInputStream();
int len=is.available();
//System.out.println("len:"+len);
byte[] bytes=new byte[len];
is.read(bytes);
String resut=new String(bytes);
//System.out.println("resut:"+resut);
if(resut!=null && resut.length()>0){
System.out.println("收到!!!resut:"+resut);
text.append(resut);
}
} catch (IOException e) {
e.printStackTrace();
}
//睡眠2秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
).start();
}
public static void main(String[] args) {
new UserClient();
}
}
⑹ NiO是什么
Java NIO框架MINA用netty性能和链接数、并发等压力测试参数好于mina。
特点:
1。NIO弥补了原来的I/O的不足,它再标准java代码中提供了高速和面向块的I/O
原力的I/O库与NIO最重要的区别是数据打包和传输方式的不同,原来的I/O以流的方式处理数据,而NIO以块的方式处理数据;
2.NIO以通道channel和缓冲区Buffer为基础来实现面向块的IO数据处理,MINA是开源的。
JavaNIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的。
Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。
Java NIO出现不只是一个技术性能的提高,会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。
如果至今还是在怀疑Java的性能,说明思想和观念已经完全落伍了,Java一两年就应该用新的名词来定义。从JDK1.5开始又要提供关于线程、并发等新性能的支持,Java应用在游戏等适时领域方面的机会已经成熟,Java在稳定自己中间件地位后,开始蚕食传统C的领域。
原理:
NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生。比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。在使用上,也在分两个方向,一个是线程处理,一个是用非线程,后者比较简单。
⑺ niop是什摸意思
全国青少年信息学奥林匹克联赛(NOIP) 全国青少年信息学奥林匹克联赛大纲 一、总则 由中国计算机学会负责组织的全国青少年信息学奥林匹克联赛(NOIP)是全国信息学奥林匹克竞赛(NOI)整个系列中的一个重要组成部分,旨在向中学生普及计算机基础知识,培养计算机科学和工程领域的后备人才。普及的重点是根据中学生的特点,培养学生学习计算机的兴趣,使得他们对信息技术的一些核心内容有更多的了解,提高他们创造性地运用程序设计知识解决实际问题的能力。对学生的能力培养将注重以下的几个方面: *想象力与创造力; *对问题的理解和分析能力; *数学能力和逻辑思维能力; *对客观问题和主观思维的口头和书面表达能力; *人文精神:包括与人的沟通能力,团队精神与合作能力,恒心和毅力,审美能力等。 二、命题程序和组织机构 命题是选拔过程的重要一环,同时对计算机的普及的内容起着导向性的作用。命题应注重趣味性、新颖性、知识性、应用性和中学生的心智特点,不直接从大学专业教材中选题。 在命题和审题工作中,坚持开放和规范的原则。在NOI科学委员会主持下成立的联赛命题委员会负责命题工作,命题委员会成员主要来自参加联赛的省( 包括直辖市、自治区,下同。每个省最多派一名委员),也可来自社会计算机界。联赛命题委员会的主要职责是提供联赛的备选题目,并承担对所提供的题目保密的责任。 1. 联赛命题委员会委员应具备如下资格: *从事一线计算机教学或信息学奥赛辅导工作两年(含)以上; *有精力和时间从事该项工作; *对此项工作有兴趣并愿意作为志愿者从事NOIP命题及其相关工作。 2. 联赛命题委员会委员的产生过程: *本人提出申请(填写表格); *中学教师需所在单位同意或省奥赛主管部门同意; *科学委员会批准,由中国计算机学会颁发聘书(每一聘期为两年)。 3. 联赛命题委员会委员的职责: *每年为NOIP提供备选题题目若干,在9月1日之前提交科学委员会; *备选试题的保密期为2年,在该段时间内不得泄密或另作他用; *搜集本省信息学奥赛的有关信息并向科学委员会通报; 题目一经提交,即表明同意授权中国计算机学会科学委员会全权处理,包括使用、修改和出版。无论是委员提交的题目还是科学委员会直接提交的题目,试题版权均归中国计算机学会所有,试题原型一旦被正式采用,中国计算机学会将出具试题录用证明。科学委员会确定当年的联赛试题,这些试题可能从备选题库中选取并做适当修改后成型,也可能直接命题。 三、竞赛形式和成绩评定 联赛分两个等级组:普及组和提高组。每组竞赛分两轮:初试和复试。 *初试形式为笔试,侧重考察学生的计算机基础知识和编程的基本能力,并对知识面的广度进行测试。初试为资格测试,各省初试成绩在本赛区前15%的学生进入复赛。 *复试形式为上机,着重考察学生对问题的分析理解能力,数学抽象能力,编程语言的能力和编程技巧、想象力和创造性等。各省联赛的等第奖在复试的优胜者中产生。 比赛中使用的程序设计语言是: *2003年:初赛:BASIC、PASCAL或C/C++;复赛:BASIC、PASCAL或C/C++。 *2004年:初赛:BASIC、PASCAL或C/C++:复赛:PASCAL或C/C++。 *2005年及之后:初赛:PASCAL或C/C++: 复赛:PASCAL或C/C++。 每年复赛结束后,各省必须在指定时间内将本省一等奖候选人的有关情况、源程序和可执行程序报送科学委员会。经复审确认后,由中国计算机学会报送中国科协和教育部备案。中国计算机学会对各省获NOIP二等奖和三等奖的分数线或比例提出指导性意见,各省可按照成绩确定获奖名单。 四、试题形式 每次联赛的试题分四组:普及组初赛题A1、普及组复赛题A2、提高组初赛题B1和提高组复赛题B2。其中,A1和B1类型相同,A2和B2类型相同,但题目不完全相同,提高组难度高于普及组。 *初赛:初赛全部为笔试,满分100分。试题由四部分组成: 1、 选择题:共20题,每题1.5分,共计30分。每题有5个备选答案,前10个题为单选题(即每题有且只有一个正确答案,选对得分),后10题为不定项选择题(即每题有1至5个正确答案,只有全部选对才得分)。