Java多线程与网络编程综合使用
生活随笔
收集整理的這篇文章主要介紹了
Java多线程与网络编程综合使用
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
處理多線程與網(wǎng)絡編程最為經(jīng)典的例子莫過于聊天室,那我就聊天室案例作為一個回顧。
首先,我們來看以下代碼:
?
package MultiTCP;import java.io.DataInputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; /** * 1、創(chuàng)建客戶端 必須指定服務器+端口 此時就在連接 * Socket(String host,int port) * 2、接收數(shù)據(jù)+發(fā)送數(shù)據(jù) */ @SuppressWarnings("all") public class Client { public static void main(String[] args) throws UnknownHostException, IOException { //1、創(chuàng)建客戶端 必須指定服務器+端口 此時就在連接 Socket client = new Socket("localhost",8888); //2、接收數(shù)據(jù) /*BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); String echo = br.readLine();//阻塞式方法 System.out.println(echo);*/ DataInputStream dis = new DataInputStream(client.getInputStream()); String echo = dis.readUTF(); System.out.println(echo); } }?
以上代碼存在的問題
服務器為一個客戶端發(fā)送數(shù)據(jù)完畢才能連接下一個客戶端。
因此,為了解決上述的問題,我們需要為服務器端創(chuàng)建多線程操作。
首先我們需要為聊天室添加發(fā)送數(shù)據(jù)和接收數(shù)據(jù)。
package CSNet;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 創(chuàng)建服務器 */ @SuppressWarnings("all") public class Server { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(9999); Socket client = server.accept(); //寫出數(shù)據(jù) //輸入流 DataInputStream dis = new DataInputStream(client.getInputStream()); String msg = dis.readUTF(); System.out.println("服務器收到"+msg); //輸出流 DataOutputStream dos = new DataOutputStream(client.getOutputStream()); dos.writeUTF("服務器發(fā)送給客戶端"+msg); dos.flush(); } }?
package CSNet;import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.UnknownHostException; /** * 創(chuàng)建客戶端:發(fā)送數(shù)據(jù)+接收數(shù)據(jù) * 寫出數(shù)據(jù):輸出流 * 讀取數(shù)據(jù):輸入流 * 輸入流與輸出流在同一個線程內(nèi),因此我們應該讓 輸入流與輸出流彼此獨立 */ @SuppressWarnings("all") public class Client { public static void main(String[] args) throws UnknownHostException, IOException { Socket client = new Socket("localhost",9999); //控制臺的輸入流 BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); DataOutputStream dos = new DataOutputStream(client.getOutputStream()); DataInputStream dis = new DataInputStream(client.getInputStream()); while(true) { String info = console.readLine(); //輸出流 dos.writeUTF(info); dos.flush(); //輸入流 String msg = dis.readUTF(); System.out.println(msg); } } }?
以上的代碼存在輸入流與輸出流在同一個線程內(nèi)問題,因此我們應該讓輸入流與輸出流彼此獨立。
接下來我們是需要實現(xiàn)多線程,讓輸入流與輸出流分離。對客戶端實現(xiàn)多線程。
客戶端發(fā)送數(shù)據(jù)
package ThreadNet;import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; /** * 發(fā)送數(shù)據(jù)線程:用于發(fā)送數(shù)據(jù) */ public class Send implements Runnable{ //控制臺的輸入流 private BufferedReader console; //管道的數(shù)據(jù)輸出流 private DataOutputStream dos; //控制線程標識 private boolean isRunning = true; //初始化 public Send() { console = new BufferedReader(new InputStreamReader(System.in)); } public Send(Socket client) { this(); try { dos = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { } } //1、從控制臺接收數(shù)據(jù) private String getMsgFromConsole() { try { return console.readLine(); } catch (IOException e) { } return ""; } /** * 1、從控制臺接收數(shù)據(jù) * 2、發(fā)送數(shù)據(jù) */ public void send() { String msg = getMsgFromConsole(); try { if(null!=msg&& !msg.equals("")) { dos.writeUTF(msg); dos.flush();//強制刷新 } } catch (IOException e) { isRunning = false;//發(fā)送失敗,提示關閉線程 CloseUtil.closeAll(dos,console);//如果不能發(fā)送成功,直接關閉流。 } } @Override public void run() { //線程體 while(isRunning) { send(); } } }?
客戶端接收數(shù)據(jù)
package ThreadNet;import java.io.DataInputStream; import java.io.IOException; import java.net.Socket;/** * 接收線程:用于接收數(shù)據(jù) */ public class Receive implements Runnable{ //管道的數(shù)據(jù)輸入流 private DataInputStream dis ; //線程標識 private boolean isRunning = true; public Receive() { } public Receive(Socket client) { try { dis = new DataInputStream(client.getInputStream()); } catch (IOException e) { isRunning = false; CloseUtil.closeAll(dis); } } //接收數(shù)據(jù)的方法 public String receive() { String msg = ""; try { msg = dis.readUTF(); } catch (IOException e) { isRunning = false; CloseUtil.closeAll(dis); } return msg; } @Override public void run() { //線程體 while(isRunning){ System.out.println(receive()); } } }?
客戶端
package ThreadNet;import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException;/** * 創(chuàng)建客戶端:發(fā)送數(shù)據(jù)+接收數(shù)據(jù) * 寫出數(shù)據(jù):輸出流 * 讀取數(shù)據(jù):輸入流 * 輸入流與輸出流在同一個線程內(nèi) 應該獨立出來 */ public class Client { public static void main(String[] args) throws UnknownHostException, IOException { Socket client = new Socket("localhost",9999); new Thread(new Send(client)).start();//一條路徑 new Thread(new Receive(client)).start();//一條路徑 } }?
服務器
package ThreadNet;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 創(chuàng)建服務器 */ public class Server { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(9999); while(true){ Socket client = server.accept(); //寫出數(shù)據(jù) //輸入流 DataInputStream dis = new DataInputStream(client.getInputStream()); //輸出流 DataOutputStream dos = new DataOutputStream(client.getOutputStream()); while(true) { String msg = dis.readUTF(); //System.out.println(msg); dos.writeUTF("服務器收到數(shù)據(jù)并返回"+msg); dos.flush(); } } } }?
關閉流
package ThreadNet;import java.io.Closeable; import java.io.IOException;/*** 關閉流的方法*/ public class CloseUtil { public static void closeAll(Closeable ... io) { for(Closeable temp:io) { if(null==temp) { try { temp.close(); } catch (IOException e) { e.printStackTrace(); } } } } }這個方仍然存在問題,服務器端只能夠一個一個的接收,必須要等到上一條執(zhí)行完,才能進入下一條,存在所謂的先后順序,并不具備多線程的功能。因此我們也需要對服務器進行多線程。
服務器
package MultiServer;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; /** * 創(chuàng)建服務器 */ public class Server { private List<MyChannel> all = new ArrayList<>(); public static void main(String[] args) throws IOException { new Server().start(); } public void start() throws IOException { ServerSocket server = new ServerSocket(9999); while(true) { Socket client = server.accept(); MyChannel channel = new MyChannel(client); all.add(channel);//統(tǒng)一管理 new Thread(channel).start();//一條道路 } } /** * 內(nèi)部類 * 一個客戶端 一條道路 * 1、輸入流 * 2、輸出流 * 3、接收數(shù)據(jù) * 4、發(fā)送數(shù)據(jù) * @author Administrator * */ class MyChannel implements Runnable { private DataInputStream dis; private DataOutputStream dos; private boolean isRunning = true; private String name; public MyChannel() { } //初始化 public MyChannel(Socket client) { try { dis = new DataInputStream(client.getInputStream()); dos = new DataOutputStream(client.getOutputStream()); this.name = dis.readUTF(); //System.out.println(this.name); this.send("歡迎進入聊天室"); sendOthers(this.name+"進入了聊天室",true); } catch (IOException e) { CloseUtil.closeAll(dos,dis); isRunning = false; } } //接收數(shù)據(jù) private String receive() { String msg = ""; try { msg = dis.readUTF(); } catch (IOException e) { CloseUtil.closeAll(dis); isRunning = false; all.remove(this);//移除自身 } return msg; } //發(fā)送數(shù)據(jù) private void send(String msg) { if(null==msg||msg.equals("")) { return; } try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { CloseUtil.closeAll(dos); isRunning = false; all.remove(this);//移除自身 } } //發(fā)送給其他客戶端 private void sendOthers(String msg,boolean sys) { //是否為私聊 約定 if(msg.startsWith("@")&& msg.indexOf(":")>-1) { //獲取name String name = msg.substring(1,msg.indexOf(":")); String contant = msg.substring(msg.indexOf(":")+1); for(MyChannel other:all) { if(other.name.equals(name)) { other.send(this.name+"對你悄悄的說:"+contant); } } } else { for(MyChannel other:all) { if(other ==this) { continue; } if(sys==true)//系統(tǒng)信息 { other.send("系統(tǒng)信息:"+msg); } else { //發(fā)送其它客戶端 other.send(this.name+"對所有人說"+msg); } } } /* //遍歷容器 for(MyChannel others:all) { if(others == this) { continue; } //發(fā)送給其他客戶端 others.send(msg); }*/ } @Override public void run() { while(isRunning) { sendOthers(receive(),false); } } } }發(fā)送信息(供客服端使用)
package MultiServer;import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; /** * 發(fā)送數(shù)據(jù)線程:用于發(fā)送數(shù)據(jù) */ public class Send implements Runnable{ //控制臺輸入流 private BufferedReader console; //管道輸出流 private DataOutputStream dos; //控制線程標識 private boolean isRunning = true; //名稱 private String name; //初始化 public Send() { console = new BufferedReader(new InputStreamReader(System.in)); } public Send(Socket client,String name) { this(); try { dos = new DataOutputStream(client.getOutputStream()); this.name = name; send(this.name); } catch (IOException e) { //e.printStackTrace(); } } //1、從控制臺接收數(shù)據(jù) private String getMsgFromConsole() { try { return console.readLine(); } catch (IOException e) { e.printStackTrace(); } return ""; } /** * 1、從控制臺接收數(shù)據(jù) * 2、發(fā)送數(shù)據(jù) */ public void send(String msg) { try { if(null!=msg&& !msg.equals("")) { dos.writeUTF(msg); dos.flush();//強制刷新 } } catch (IOException e) { //e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dos,console); } } @Override public void run() { while(isRunning) { send( getMsgFromConsole()); } } }接收信息(供客服端使用)
package MultiServer;import java.io.DataInputStream; import java.io.IOException; import java.net.Socket;/** * 接收線程:用于接收數(shù)據(jù) */ public class Receive implements Runnable{ //管道的數(shù)據(jù)輸入流 private DataInputStream dis ; //線程標識 private boolean isRunning = true; public Receive() { } public Receive(Socket client) { try { dis = new DataInputStream(client.getInputStream()); } catch (IOException e) { isRunning = false; CloseUtil.closeAll(dis); } } //接收數(shù)據(jù)的方法 public String receive() { String msg = ""; try { msg = dis.readUTF(); } catch (IOException e) { isRunning = false; CloseUtil.closeAll(dis); } return msg; } @Override public void run() { //線程體 while(isRunning){ System.out.println(receive()); } } }客戶端
package MultiServer;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; /** * 創(chuàng)建客戶端:發(fā)送數(shù)據(jù)+接收數(shù)據(jù) * 寫出數(shù)據(jù):輸出流 * 讀取數(shù)據(jù):輸入流 * 輸入流與輸出流在同一個線程內(nèi) 應該獨立出來 * 加入名稱 */ public class Client { public static void main(String[] args) throws IOException { System.out.println("請輸入用戶名:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String name = br.readLine(); if(name.equals("")) { return; } Socket client = new Socket("localhost",9999); new Thread(new Send(client,name)).start();//一條路徑 new Thread(new Receive(client)).start();//一條路徑 } }關閉流
package MultiServer;import java.io.Closeable; import java.io.IOException;/*** 關閉流的方法*/ public class CloseUtil { public static void closeAll(Closeable ... io) { for(Closeable temp:io) { if(null==temp) { try { temp.close(); } catch (IOException e) { e.printStackTrace(); } } } } }運行結果:
Client1
Client2
轉載于:https://www.cnblogs.com/lengzhijun/p/4580271.html
總結
以上是生活随笔為你收集整理的Java多线程与网络编程综合使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黑马程序员-----集合框架类(四) 高
- 下一篇: 对图片对比度和亮度的理解