多线程Java Socket编程

逐客教我 贡献于2013-05-07

作者 微软中国  创建于2010-08-17 12:52:00   修改者微软中国  修改于2010-08-19 02:11:00字数10343

文档摘要:多线程JavaSocket编程示例这篇做为学习孙卫琴《Java网络编程精解》的学习笔记吧.其中采用Java5的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送请求.
关键词:

多线程Java Socket编程示例这篇做为学习孙卫琴<>的学习笔记吧.其中采用Java 5的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送请求. 接口Executor void execute(Runnable command)           在未来某个时间执行给定的命令。 接口ExecutorService(继承Excutor接口) Future submit(Callable task)           提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。  Future submit(Runnable task)           提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 Future submit(Runnable task, T result)           提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 工厂类Executors static ExecutorService newCachedThreadPool()           创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)           创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。 static ExecutorService newFixedThreadPool(int nThreads)           创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。 static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)           创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。 static ExecutorService newSingleThreadExecutor()           创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)           创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的 ThreadFactory 创建新线程。 接口Future boolean cancel(boolean mayInterruptIfRunning)           试图取消对此任务的执行。  V get()           如有必要,等待计算完成,然后获取其结果。  V get(long timeout, TimeUnit unit)           如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。  boolean isCancelled()           如果在任务正常完成前将其取消,则返回 true。  boolean isDone()           如果任务已完成,则返回 true。 类 ServerSocket  Socket accept()           侦听并接受到此套接字的连接。 类 Socket  void connect(SocketAddress endpoint)           将此套接字连接到服务器。  void connect(SocketAddress endpoint, int timeout)           将此套接字连接到服务器,并指定一个超时值。  InetAddress getLocalAddress()           获取套接字绑定的本地地址。  int getLocalPort()           返回此套接字绑定到的本地端口。  SocketAddress getLocalSocketAddress()           返回此套接字绑定的端点的地址,如果尚未绑定则返回 null。  InputStream getInputStream()           返回此套接字的输入流。  OutputStream getOutputStream()           返回此套接字的输出流。  int getPort()           返回此套接字连接到的远程端口。 1.服务端 package sterning; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.*; import java.util.concurrent.*; public class MultiThreadServer {     private int port=8821;     private ServerSocket serverSocket;     private ExecutorService executorService;//线程池     private final int POOL_SIZE=10;//单个CPU线程池大小          public MultiThreadServer() throws IOException{         serverSocket=new ServerSocket(port);         //Runtime的availableProcessor()方法返回当前系统的CPU数目.         executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);//工厂类创建固定线程数(CPU核心数*每个U 线程池大小)的线程池         System.out.println("服务器启动");     }          public void service(){//服务方法负责打开端口,执行服务器线程方法         while(true){             Socket socket=null;//客户端请求服务器打开的socket             try {                 //接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接                 socket=serverSocket.accept();                 executorService.execute(new Handler(socket));//连接后执行excute()                              } catch (Exception e) {                 e.printStackTrace();             }         }     }          public static void main(String[] args) throws IOException {         new MultiThreadServer().service();     } } class Handler implements Runnable{     private Socket socket;     public Handler(Socket socket){//传一个socket进来         this.socket=socket;     }     private PrintWriter getWriter(Socket socket) throws IOException{         OutputStream socketOut=socket.getOutputStream();         return new PrintWriter(socketOut,true);     }     private BufferedReader getReader(Socket socket) throws IOException{         InputStream socketIn=socket.getInputStream();         return new BufferedReader(new InputStreamReader(socketIn));     }     public String echo(String msg){         return "echo:"+msg;     }     public void run(){//线程池中execute()就执行这个方法         try {             System.out.println("New connection accepted "+socket.getInetAddress()+":"+socket.getPort());             BufferedReader br=getReader(socket);//获取输入流             PrintWriter pw=getWriter(socket);//获取输出流             String msg=null;             while((msg=br.readLine())!=null){//读输入流                 System.out.println(msg);                 pw.println(echo(msg));                 if(msg.equals("bye"))                     break;             }         } catch (IOException e) {             e.printStackTrace();         }finally{             try {                 if(socket!=null)                     socket.close();             } catch (IOException e) {                 e.printStackTrace();             }         }     } } 2.客户端 package sterning; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MultiThreadClient {          public static void main(String[] args) {         int numTasks = 10;                  ExecutorService exec = Executors.newCachedThreadPool(); //客户端创建可变数量的线程池         for (int i = 0; i < numTasks; i++) {//客户端负责执行自己的线程任务             exec.execute(createTask(i));         }     }     // 定义一个简单的任务     private static Runnable createTask(final int taskID) {         return new Runnable() {             private Socket socket = null;             private int port=8821;             public void run() {                 System.out.println("Task " + taskID + ":start");                 try {                                         socket = new Socket("localhost", port);//客户端建立socket                     // 发送关闭命令                     OutputStream socketOut = socket.getOutputStream();                     socketOut.write("shutdown\r\n".getBytes());                     // 接收服务器的反馈                     BufferedReader br = new BufferedReader(                             new InputStreamReader(socket.getInputStream()));                     String msg = null;                     while ((msg = br.readLine()) != null)//读取输入流内容                         System.out.println(msg);                 } catch (IOException e) {                                         e.printStackTrace();                 }             }         };     } } 从而实现了多个客户端向服务器端发送请求,服务器端采用多线程的方式来处理的情况.再结合我之前的例子---Java基于Socket文件传输示例,就可以实现多线程文件的传输了 Java基于Socket文件传输示例 最近需要进行网络传输大文件,于是对基于socket的文件传输作了一个初步的了解。在一位网友提供的程序基础上,俺进行了一些加工,采用了缓冲输入/输出流来包装输出流,再采用数据输入/输出输出流进行包装,加快传输的速度。废话少说,先来看服务器端的程序。 类 DataOutputStream void writeLong(long v)           将一个 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。 void writeUTF(String str)           以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。 void write(byte[] b)           将数组 b 中的所有字节写入输出流。  void write(byte[] b, int off, int len)           将数组 b 中从off开始的 len 个字节按顺序写入输出流。 void flush()           清空此数据输出流 类 DataInputStream  int read(byte[] b)           从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。 byte readByte()           读取并返回一个输入字节。 String readUTF()           读入一个已使用 UTF-8 修改版格式编码的字符串。 类 FileOutputStream 构造方法摘要 FileOutputStream(File file)           创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 FileOutputStream(String name)           创建一个向具有指定名称的文件中写入数据的输出文件流。 1.服务器端 package sterning; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerTest {     int port = 8821;     void start() {         Socket s = null;         try {             ServerSocket ss = new ServerSocket(port);             while (true) {                 // 选择进行传输的文件                 String filePath = "D:\\lib.rar";                 File fi = new File(filePath);                 System.out.println("文件长度:" + (int) fi.length());                 // public Socket accept() throws                 // IOException侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。                 s = ss.accept();//接受客户端连接,建立一个通信端口                 System.out.println("建立socket链接");                 DataInputStream dis = new DataInputStream(new BufferedInputStream(s.getInputStream()));//获取输入流                 dis.readByte();                 DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));//硬盘文件输入流                 DataOutputStream dos = new DataOutputStream(s.getOutputStream());//获取输出流                 //将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In Java 4th里有现成的代码。                 dos.writeUTF(fi.getName());//输出文件名                 dos.flush();                 dos.writeLong((long) fi.length());//输出文件长度                 dos.flush();                 int bufferSize = 8192;                 byte[] buf = new byte[bufferSize];//设置文件输入流的缓冲大小                 while (true) {                     int read = 0;                     if (fis != null) {                         read = fis.read(buf);//从服务器硬盘读入文件,返回一个int变量,等于-1表示读取完成                     }                     if (read == -1) {//读完则退出while循环                         break;                     }                    dos.write(buf, 0, read);//将缓冲buf中的read个字节写入输出流,输出 到客户端(将刚读入的文件写入到输出流)                 }                 dos.flush();//清空输出流                 // 注意关闭socket链接哦,不然客户端会等待server的数据过来,                 // 直到socket超时,导致数据不完整。                                 fis.close();//关闭文件读入流                 s.close();//关闭socket端口                                 System.out.println("文件传输完成");             }         } catch (Exception e) {             e.printStackTrace();         }     }     public static void main(String arg[]) {         new ServerTest().start();     } } 2.socket的Util辅助类 package sterning; import java.net.*; import java.io.*; public class ClientSocket {     private String ip;     private int port;     private Socket socket = null;     DataOutputStream out = null;     DataInputStream getMessageStream = null;     public ClientSocket(String ip, int port) {//传入ip和端口号         this.ip = ip;         this.port = port;     }     /**      * 创建socket连接      *       * @throws Exception      *             exception      */     public void CreateConnection() throws Exception {         try {             socket = new Socket(ip, port);//创建客户端socket         } catch (Exception e) {             e.printStackTrace();             if (socket != null)                 socket.close();             throw e;         } finally {         }     }     public void sendMessage(String sendMessage) throws Exception {//String参数,表示操作系统类型         try {             out = new DataOutputStream(socket.getOutputStream());             if (sendMessage.equals("Windows")) {//输出流根据系统不同,写入不同信息                 out.writeByte(0x1);                 out.flush();                 return;             }             if (sendMessage.equals("Unix")) {                 out.writeByte(0x2);                 out.flush();                 return;             }             if (sendMessage.equals("Linux")) {                 out.writeByte(0x3);                 out.flush();             } else {                 out.writeUTF(sendMessage);                 out.flush();             }         } catch (Exception e) {             e.printStackTrace();             if (out != null)                 out.close();             throw e;         } finally {         }     }     public DataInputStream getMessageStream() throws Exception {         try {             getMessageStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));            return getMessageStream;//返回输入流(下载文件,即接收来自服务器的输出流)         } catch (Exception e) {             e.printStackTrace();             if (getMessageStream != null)                 getMessageStream.close();             throw e;         } finally {         }     }     public void shutDownConnection() {         try {             if (out != null)                 out.close();             if (getMessageStream != null)                 getMessageStream.close();             if (socket != null)                 socket.close();         } catch (Exception e) {         }     } } 3.客户端 package sterning; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileOutputStream; public class ClientTest {     private ClientSocket cs = null;     private String ip = "localhost";// 设置成服务器IP     private int port = 8821;     private String sendMessage = "Windows";     public ClientTest() {//构造方法包含3个步骤         try {             if (createConnection()) { //如果已建立连接,则发送系统信息并下载文件                 sendMessage();                 getMessage();             }         } catch (Exception ex) {             ex.printStackTrace();         }     }     private boolean createConnection() {         cs = new ClientSocket(ip, port);//调用客户端工具类,传入ip和端口号         try {             cs.CreateConnection();//建立连接,即创建客户端socket             System.out.print("连接服务器成功!" + "\n");             return true;         } catch (Exception e) {             System.out.print("连接服务器失败!" + "\n");             return false;         }     }     private void sendMessage() {         if (cs == null)             return;         try {             cs.sendMessage(sendMessage);//就是将系统信息发到服务器         } catch (Exception e) {             System.out.print("发送消息失败!" + "\n");         }     }     private void getMessage() {//读取输入流,就是下载文件,并保存到本机         if (cs == null)             return;         DataInputStream inputStream = null;         try {             inputStream = cs.getMessageStream();         } catch (Exception e) {             System.out.print("接收消息缓存错误\n");             return;         }         try {             //本地保存路径,文件名会自动从服务器端继承而来。             String savePath = "E:\\";             int bufferSize = 8192;             byte[] buf = new byte[bufferSize];             int passedlen = 0;             long len=0;                          savePath += inputStream.readUTF();             DataOutputStream fileOut = new DataOutputStream(new BufferedOutputStream(new BufferedOutputStream(new FileOutputStream(savePath))));//向文件名为savePath的文件,创建用于写入数据的输出流             len = inputStream.readLong();                          System.out.println("文件的长度为:" + len + "\n");             System.out.println("开始接收文件!" + "\n");                                  while (true) {                 int read = 0;                 if (inputStream != null) {//从输入流读入文件                     read = inputStream.read(buf);                 }                 passedlen += read;//文件接收进度条                 if (read == -1) {                     break;                 }                 //下面进度条本为图形界面的prograssBar做的,这里如果是打文件,可能会重复打印出一些相同的百分比                 System.out.println("文件接收了" +  (passedlen * 100/ len) + "%\n");                 fileOut.write(buf, 0, read);//一边读入,一边通过文件输出流保存的硬盘             }             System.out.println("接收完成,文件存为" + savePath + "\n");             fileOut.close();         } catch (Exception e) {             System.out.println("接收消息错误" + "\n");             return;         }     }     public static void main(String arg[]) {         new ClientTest();     } } 这就实现了从服务器端向客户端发送文件的过程,当然,反过来,也一样.稍有不同.代码中对跨平台的细节没有实现,有时间或兴趣的朋友可以提供一下.

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档