網絡編程的基本模型是Client/Server模型,也就是兩個進程之間進行相互通訊,其中服務端提供位置信息(綁定的IP地址和監聽端口),客戶端經過鏈接操做向服務器監聽的地址發起鏈接請求,若是鏈接創建成功 ,雙方就能夠經過Socket進行通訊。java
在傳統的BIO網絡編程中,ServerSocket負責綁定IP地址,啓動監聽端口;Socket負責發起鏈接操做。鏈接成功以後,雙方經過輸入和輸出流進行同步阻塞式通訊。編程
下面咱們會一步一步的實現BIO的網絡編程,而且對代碼進行不斷的修改和優化。服務器
正如上文所言,進行BIO網絡編程須要Server和Client,客戶端咱們只編寫一個版本,保證可以向服務器發送請求,而服務端咱們會從最基本的只可以進行一次請求處理的版本開始,不斷的完善。網絡
package nio;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
public class BIOClient {
public static void main(String[] args) throws Exception{
for (int i=0;i<=99;i++){
System.out.println(sendMsg("你好"+i));
}
}
public static String sendMsg(String msg) throws Exception{
// 建立socket 只負責發送請求 不須要監聽
Socket socket = new Socket();
// 鏈接服務器
socket.connect(new InetSocketAddress("localhost",9999));
// 寫入數據給服務器
OutputStream outputStream = socket.getOutputStream();
// java 基礎的IO操做
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(msg);
printWriter.flush();
// 關閉輸出流
socket.shutdownOutput();
// 接受服務器的響應信息
InputStream inputStream = socket.getInputStream();
// java 基礎的IO操做
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer stringBuffer = new StringBuffer();
String value = null;
while ((value=bufferedReader.readLine())!=null){
stringBuffer.append(value);
}
socket.close();
return "客戶端收到:"+ stringBuffer.toString();
}
}
複製代碼
服務器啓動一次就關閉多線程
優化方向:保證可以連續的處理請求併發
public static void test1() throws Exception{
// 建立一個ServerSocket
ServerSocket ss = new ServerSocket();
// 綁定服務器監聽端口
ss.bind(new InetSocketAddress(9999));
//表明服務器和客戶端的會話 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)
// socket阻塞的 accept會監聽有沒有請求
System.out.println("我在9999監聽");
Socket socket = ss.accept();
System.out.println("請求處理");
//獲取請求數據 InputStream
InputStream inputStream = socket.getInputStream();
// java 基礎的IO操做
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer stringBuffer = new StringBuffer();
String value = null;
while ((value=bufferedReader.readLine())!=null){
stringBuffer.append(value);
}
System.out.println("服務器收到:"+ stringBuffer.toString());
// 獲取響應 OutputStream
OutputStream outputStream = socket.getOutputStream();
// java 基礎的IO操做
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println("你好,我是服務器");
printWriter.flush();
// 關閉資源
socket.close();
}
複製代碼
使用死循環,保證能夠一直處理請求。app
缺點:socket
升級方向:多線程ide
public static void test2() throws Exception{
// 建立一個ServerSocket
ServerSocket ss = new ServerSocket();
// 綁定服務器監聽端口
ss.bind(new InetSocketAddress(9999));
//表明服務器和客戶端的會話 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)
// socket阻塞的 accept會監聽有沒有請求
while (true){
System.out.println("我在9999監聽");
Socket socket = ss.accept();
System.out.println("請求處理");
//獲取請求數據 InputStream
InputStream inputStream = socket.getInputStream();
// java 基礎的IO操做
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer stringBuffer = new StringBuffer();
String value = null;
while ((value=bufferedReader.readLine())!=null){
stringBuffer.append(value);
}
System.out.println("服務器收到:"+ stringBuffer.toString());
// 獲取響應 OutputStream
OutputStream outputStream = socket.getOutputStream();
// java 基礎的IO操做
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println("你好,我是服務器");
printWriter.flush();
// 關閉資源
socket.close();
}
}
複製代碼
多線程處理 一旦有請求過來就交給一個新的線程處理 缺點:高併發
改進方向:使用線程池
public static void test3() throws Exception{
// 建立一個ServerSocket
ServerSocket ss = new ServerSocket();
// 綁定服務器監聽端口
ss.bind(new InetSocketAddress(9999));
//表明服務器和客戶端的會話 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)
// socket阻塞的 accept會監聽有沒有請求
while (true){
System.out.println("我在9999監聽");
Socket socket = ss.accept();
// 多線程處理 一旦有請求過來就交給一個新的線程處理
SocketProcessRunable socketProcessRunable = new SocketProcessRunable(socket);
Thread thread = new Thread(socketProcessRunable);
thread.start();
}
}
class SocketProcessRunable implements Runnable{
private Socket socket;
public SocketProcessRunable(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
Thread.sleep(1000);
//獲取請求數據 InputStream
InputStream inputStream = socket.getInputStream();
// java 基礎的IO操做
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer stringBuffer = new StringBuffer();
String value = null;
while ((value=bufferedReader.readLine())!=null){
stringBuffer.append(value);
}
System.out.println("服務器收到:"+ stringBuffer.toString());
// 獲取響應 OutputStream
OutputStream outputStream = socket.getOutputStream();
// java 基礎的IO操做
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println("你好,我是服務器");
printWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
複製代碼
使用線程池管理線程
public static void main(String[] args) throws Exception{
// 建立線程池 Executors建立線程的缺點
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 建立一個ServerSocket
ServerSocket ss = new ServerSocket();
// 綁定服務器監聽端口
ss.bind(new InetSocketAddress(9999));
//表明服務器和客戶端的會話 (InputStream = HttpServletRequest | OutputStream = HttpServletResponse)
// socket阻塞的 accept會監聽有沒有請求
while (true){
System.out.println("我在9999監聽");
Socket socket = ss.accept();
// 多線程處理 一旦有請求過來就交給一個新的線程處理
SocketProcessRunable socketProcessRunable = new SocketProcessRunable(socket);
// 將任務交給線程池處理
executorService.submit(socketProcessRunable);
}
}
class SocketProcessRunable implements Runnable{
private Socket socket;
public SocketProcessRunable(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
Thread.sleep(1000);
//獲取請求數據 InputStream
InputStream inputStream = socket.getInputStream();
// java 基礎的IO操做
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer stringBuffer = new StringBuffer();
String value = null;
while ((value=bufferedReader.readLine())!=null){
stringBuffer.append(value);
}
System.out.println("服務器收到:"+ stringBuffer.toString());
// 獲取響應 OutputStream
OutputStream outputStream = socket.getOutputStream();
// java 基礎的IO操做
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println("你好,我是服務器");
printWriter.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
複製代碼
我不能保證每個地方都是對的,可是能夠保證每一句話,每一行代碼都是通過推敲和斟酌的。但願每一篇文章背後都是本身追求純粹技術人生的態度。
永遠相信美好的事情即將發生。