简易命令行界面的C/S聊天室
最近幾天復(fù)習(xí)了下java網(wǎng)絡(luò)編程socket使用我覺得雖然下面的內(nèi)容很基礎(chǔ)但是如果想要做出個好的東西想要快速掌握以后要學(xué)習(xí)的先要把基礎(chǔ)打牢
如果基礎(chǔ)打得好那么將來學(xué)習(xí)新的知識會很快,其實都是同理的。
如果大神能發(fā)揮下,拓展下完善下功能那就更好了,請在下面留下您的想法我會一直維護我的這些文章。
TCP?協(xié)議基礎(chǔ)
IP協(xié)議是Internet的使用的一個關(guān)鍵協(xié)議,全稱是Internet?Protocol,即Internet協(xié)議通常簡稱IP協(xié)議通過IP協(xié)議,從而使Internet成為一個允許連接不同類型計算機的不同操作系統(tǒng)的網(wǎng)絡(luò)。如果想要兩臺計算機通信那么就要使用相同的語言?那么就是用IP協(xié)議但是只保證計算機能發(fā)送接受分組數(shù)據(jù),IP協(xié)議負責(zé)將消息從一個主機發(fā)送到另一個主機,消息在傳送過程中被分割成包。但是這樣只是解決了他們之間的發(fā)送和接收數(shù)據(jù)但是還不能解決數(shù)據(jù)分組在數(shù)據(jù)傳輸過程中出現(xiàn)的問題。所以就需要使用TCP協(xié)議以保證提供可靠并且無差錯的通信服務(wù)。
TCP協(xié)議是面向連接的端對端的協(xié)議。這是因為他對兩臺計算機之間的鏈接起到了重要的作用建立的鏈接用于發(fā)送和接收數(shù)據(jù)的虛擬鏈路
TCP和IP協(xié)議的功能雖然不盡相同,也可以分開使用,但是他們是在同一時期作為一個協(xié)議來設(shè)計的,并且在功能上也是互補的。只有兩者結(jié)合起來才能保證internet在復(fù)雜的環(huán)境下正常的運行凡事要連接到internet的計算機都必須同時安裝和使用這兩個協(xié)議因此唱吧這兩個協(xié)議叫做TCP/IP協(xié)議
使用serverSocket創(chuàng)建TCP服務(wù)器端
在兩個通信實體之間沒有建立虛擬鏈路之前必須先有一個通信實體先做出“主動姿態(tài)”主動地接受來自其他實體的連接請求。Java中接收其他的通信實體連接請求的類是ServerSocket,serverSocket用于監(jiān)聽來自socket端的連接,如果沒有連接,他將一直處于等待狀態(tài),serverSocket包含一個監(jiān)聽來自客戶端請求的方法
Socket?accept():如果接收到一個客戶端的Socket的鏈接的請求,該方法返回一個與客戶端對應(yīng)的socket否則該方法一直處于等待狀態(tài)線程也被阻塞
為了創(chuàng)建serversocket對像,提供了如下幾個構(gòu)造器
serverSocket(int?port)指定的端口創(chuàng)建一個serverSocket對像該端口應(yīng)該有一個有效的端口整數(shù)
serverSocket(int?port,int?backlog):增加一個用來改變連接隊列長度的參數(shù)backlog
當(dāng)serverSocket使用完畢后,應(yīng)使用serverSocket的close()方法關(guān)閉該serverSocket。在通常情況下
?
服務(wù)器不用改制接受一個客戶端的請求,而應(yīng)該不斷地接受來自客戶端的所有的請求,所以java程序通常會循環(huán)的不斷的調(diào)用serverSocket的accept()方法
使用socket進行通信
客戶端通常可以使用socket的構(gòu)造器連接到指定的服務(wù)器,socket通常可以使用給定的兩個構(gòu)造器連接到相應(yīng)的主機或者是相應(yīng)的IP地址的服務(wù)器這樣就能實現(xiàn)對話
--
加入多線程
前面的Server和Client只是進行了簡單的通信操作:服務(wù)器端接收到客戶端的連接之后,服務(wù)器端向客戶端輸出了一個字符串,而客戶但也只是讀取服務(wù)器端的字符串后就退出了,實際應(yīng)用中的客戶端可能根據(jù)需要和服務(wù)器端保持長時間通信,即服務(wù)器端需要不斷的讀取客戶端數(shù)據(jù),并向客戶端寫入數(shù)據(jù);客戶端也需要不斷的讀取服務(wù)器端的數(shù)據(jù),并向服務(wù)器端寫入數(shù)據(jù)。
在使用傳統(tǒng)的BufferReader的readLine()方法讀取數(shù)據(jù)時,在該方法成功返回之前,線程被阻塞,程序無法執(zhí)行。考慮到這個因素,服務(wù)器端應(yīng)該為每個Socket啟動一個線程,每個線程負責(zé)與一個客戶端進行通信
客戶端讀取服務(wù)器端數(shù)據(jù)的縣城同樣會被阻塞,所以系統(tǒng)應(yīng)該單獨啟動一個線程。該線程專門負責(zé)讀取服務(wù)器端的數(shù)據(jù)。
現(xiàn)在考慮實現(xiàn)一個命令行的界面的C/S聊天室應(yīng)用,服務(wù)器端應(yīng)該包含多個線程,每個Socket對應(yīng)一個線程,該線程負責(zé)讀取Socket對應(yīng)輸入流的數(shù)據(jù)。并將讀取到的數(shù)據(jù)向每個Socket輸出流發(fā)送一次(將一個客戶端的數(shù)據(jù)廣播給其他客戶端)需要在服務(wù)器端使用list保存所有的Socket
服務(wù)器端的實現(xiàn):
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.administrator.openinternet;import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List;/*** Created by Administrator on 2015/7/23.* 服務(wù)器端的程序*/ public class javaSocket {public static List<Socket> socketList = Collections.synchronizedList(new ArrayList<Socket>());public static void main (String [] args) throws IOException {ServerSocket ss = new ServerSocket(30000);while(true){Socket s = ss.accept();socketList.add(s);new Thread( new ServerThread(s)).start();}} } </span></span>
服務(wù)器端的線程類:
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.administrator.openinternet;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.SocketException;/*** Created by Administrator on 2015/7/23.* 服務(wù)器端的線程*/ public class ServerThread implements Runnable {Socket s = null;BufferedReader br = null;public ServerThread(Socket s){this.s = s ;try {br = new BufferedReader(new InputStreamReader(s.getInputStream()));//創(chuàng)建并讀取流} catch (IOException e) {e.printStackTrace();}}/*** Starts executing the active part of the class' code. This method is* called when a thread is started that has been created with a class which* implements {@code Runnable}.*/@Overridepublic void run(){try{String content = null;while ((content = readFromClient())!=null){for(Socket s:javaSocket.socketList){PrintStream ps = new PrintStream(s.getOutputStream());}}}catch (IOException e){e.printStackTrace();}}private String readFromClient() {try{return br.readLine();}catch (IOException e) {e.printStackTrace();javaSocket.socketList.remove(s);//移除socketList中的數(shù)據(jù)三}return null;} } </span></span> 客戶端實現(xiàn):
<span style="font-size:18px;">package com.example.administrator.openinternet;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket;/*** Created by Administrator on 2015/7/23.* 我的客戶端的程序*/ public class MyClient {public static void main(String [] args) throws IOException{Socket s = new Socket("127.0.0.1",30000);new Thread( new ClientThread(s)).start();PrintStream ps = new PrintStream(s.getOutputStream());String line = null;BufferedReader br = new BufferedReader( new InputStreamReader(System.in));while ((line = br.readLine())!=null){ps.println(line);}} } </span>
客戶端線程:
<span style="font-size:18px;">package com.example.administrator.openinternet;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket;/*** Created by Administrator on 2015/7/23.* 客戶端的線程*/ public class ClientThread implements Runnable {private Socket s ;BufferedReader br = null;public ClientThread(Socket s) throws IOException {this.s = s ;br = new BufferedReader(new InputStreamReader(s.getInputStream()));}/*** Starts executing the active part of the class' code. This method is* called when a thread is started that has been created with a class which* implements {@code Runnable}.*/@Overridepublic void run(){try{String content = null;while ((content = br.readLine())!=null){System.out.println(content);}}catch (Exception e){e.printStackTrace();}} } </span>
這就實現(xiàn)了簡單的回話,其實可以繼續(xù)擴展比如實現(xiàn)客戶端和服務(wù)器端的數(shù)據(jù)的傳遞過幾天更新過來
總結(jié)
以上是生活随笔為你收集整理的简易命令行界面的C/S聊天室的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个优秀开发者如何才能变得伟大?
- 下一篇: 安卓机更新系统会卡吗_都说安卓手机用一两