小小聊天室,慢慢的回忆啊!(TCP 通信实现)
生活随笔
收集整理的這篇文章主要介紹了
小小聊天室,慢慢的回忆啊!(TCP 通信实现)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 前言
- 一、TCP 協議
- 二、 TCP 通信 的實現
- “ 請求- 響應 ” 模式:
- 通過 Socket 的編程順序:
- 基于TCP協議的Socket編程,實現單向通訊
- 通過數據流改進代碼
- 序列化涉及的類和接口(io流知識回顧一下)
- 基于TCP協議的Socket編程,實現雙向通訊(通過多線程模擬多個用戶請求登錄)
- つづく
前言
之前學網絡編程這塊,就是感覺云里霧里,就想對老師說一句:你說啥呢?這兩天學框架,遇到個bug怎么也是解決不了了;這兩天還趕上元旦,老師們都放假;進行不下去就回來復習復習吧!看看最頭疼的網絡編程;重新在看一遍,還真有種知新而溫故的感覺!廢話不多說,我們看代碼;
一、TCP 協議
TCP(Transfer Control Protocol)是面向連接的,所謂面向連接,就是當計算機雙方通信時必需經過先建立連接,然后傳送數據,最后拆除連接三個過程。二、 TCP 通信 的實現
在網絡通訊中,第一次主動發起通訊的程序被稱作客戶端(Client)程序,簡稱客戶端,而在第一次通訊中等待連接的程序被稱作服務器端(Server)程序,簡稱服務器。一旦通訊建立,則客戶端和服務器端完全一樣,沒有本質的區別。
“ 請求- 響應 ” 模式:
Socket 類:發送 TCP 消息。
ServerSocket 類:創建服務器。
通過 Socket 的編程順序:
基于TCP協議的Socket編程,實現單向通訊
代碼如下:
服務端
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;/*** 服務器類* */ public class ServerTest {public static void main(String[] args) throws IOException { // 創建serverSocket對象,并指定端口;ServerSocket ss = new ServerSocket(9999); // 利用accept()方法,進行監聽 返回一個Socket對象Socket client = ss.accept(); // 接收數據(獲取輸入流)由于接收到是字節(也就是數字)需要轉換成字符read:從輸入流讀取數據的下一個字節。 InputStream is = client.getInputStream();System.out.println((char)is.read()); // 發出響應(獲取輸出流)write():將 b.length字節從指定的字節數組寫入此輸出流。OutputStream os = client.getOutputStream();os.write("收到".getBytes()); // 關閉流if(os!=null) {os.close();}if(is!=null) {is.close();}if(client!=null) {client.close();}}}客戶端
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket;/*** 客戶類* */ public class ClientTest {public static void main(String[] args) throws IOException { // 創建Socket對象Socket socket = new Socket("192.168.10.102",9999); // 輸出數據OutputStream os = socket.getOutputStream(); // write()中的參數只能是,字符類型的os.write('a'); // 接收響應InputStream is = socket.getInputStream();byte[] b = new byte[1024];//中轉站,存儲讀到的數據int len = 0;//讀到的個數,當個數為-1時,證明沒有數據;if((len=is.read(b))!=-1) { // 利用String的構造方法,將讀到的數據輸出到控制臺System.out.println(new String(b,0,len));} // 關閉流if(is!=null) {is.close();}if(os!=null) {os.close();}if(socket!=null) {socket.close();}}}輸出效果
通過數據流改進代碼
代碼如下:
服務端
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;/*** 服務器類* */ public class ServerTest2 {public static void main(String[] args) throws IOException { // 創建serverSocket對象,并指定端口;ServerSocket ss = new ServerSocket(9999); // 利用accept()方法,進行監聽 返回一個Socket對象Socket client = ss.accept(); // 接收數據 獲取數據輸入流 數據流的參數需要一個字節流DataInputStream dis = new DataInputStream(client.getInputStream());System.out.println(dis.readUTF()); // 發出響應(獲取數據輸出流)DataOutputStream dos = new DataOutputStream(client.getOutputStream());dos.writeUTF("收到"); // 關閉流if(dos!=null) {dos.close();}if(dis!=null) {dis.close();}if(client!=null) {client.close();}if(ss!=null) {ss.close();}}}客戶端
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket;/*** 客戶類* */ public class ClientTest2 {public static void main(String[] args) throws IOException { // 創建Socket對象Socket socket = new Socket("192.168.10.102",9999); // 輸出數據 使用數據流進行數據的傳輸 參數需要一個字節流DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); // writeUTF()是寫入的方法;dos.writeUTF("hello world"); // 接收響應DataInputStream dis = new DataInputStream(socket.getInputStream()); // readUTF()是讀取數據的方法System.out.println(dis.readUTF()); // 關閉流if(dis!=null) {dis.close();}if(dos!=null) {dos.close();}if(socket!=null) {socket.close();}}}運行效果
序列化涉及的類和接口(io流知識回顧一下)
基于TCP協議的Socket編程,實現雙向通訊(通過多線程模擬多個用戶請求登錄)
創建兩個項目(服務器項目、客戶端項目)
服務器項目
User類
import java.io.Serializable;public class User implements Serializable{ // 必須要繼承Serializable接口 , 否則不能被序列化//為了防止讀寫的序列化id不同,一定要指定一個固定的序列id 最好不要選擇默認的idprivate static final long serialVersionUID = 8251855228567334134L;private String name;private String password;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public static long getSerialversionuid() {return serialVersionUID;}public User(String name, String password) {super();this.name = name;this.password = password;}public User() {super();}}服務器類
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import com.bjsxt.thread.ServerThread;/*** 服務器類* */ public class Server {public static void main(String[] args) throws IOException, ClassNotFoundException{ // 常見ServerSocket對象; 并指定端口號ServerSocket ss = new ServerSocket(10000); // 監聽客戶端 accept()方法進行監聽 并返回一個Socket對象 // 需要使用循環來監聽,不能只監聽一次while(true) {Socket client = ss.accept(); // 創建線程對象ServerThread st = new ServerThread(client); // 開啟線程new Thread(st).start();}} }添加線程類ServerThread
import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.net.Socket; import com.bjsxt.pojo.User;/*** 將獲取每一個客戶端都要執行的代碼,封裝到該類中,并實現Runnable接口,完成多線程* */public class ServerThread implements Runnable{private Socket client;public ServerThread(Socket client) {super();this.client = client;} // 線程中的異常必須處理掉,不能拋出;@Overridepublic void run() { // 想要看到誰在請求登錄必須要在線程類的方法中添加 ,如果在服務其中添加會出現main請求登錄的字樣System.out.println(Thread.currentThread().getName()+"正在請求登錄");// 獲取對象輸入流 需要一個字節流ObjectInputStream ois = null;// 獲取數據輸出流 響應是字符串 所以用數據輸出流 參數需要一個字節流DataOutputStream dos = null;try {ois = new ObjectInputStream(client.getInputStream());// 獲取信息 返回一個object對象,將其轉換為user對象User user = (User)ois.readObject();// 通過getInetAddress()方法獲取InetAddress對象,并獲取客戶端信息;System.out.println(client.getInetAddress().getHostAddress()+"請求登錄"+"\t用戶名:"+user.getName()+"\t密碼:"+user.getPassword());dos = new DataOutputStream(client.getOutputStream());// 產生響應 判斷用戶名與密碼是否正確String str = null;if("miwa".equals(user.getName())&&"miwa".equals(user.getPassword())) {str = "登錄成功";}else {str = "用戶名或密碼錯誤";} dos.writeUTF(str);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} // 關閉流 倒著關if(dos!=null) {try {dos.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(ois!=null) {try {ois.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(client!=null) {try {client.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}客戶端項目
User類
import java.io.Serializable;public class User implements Serializable{ // 必須要繼承Serializable接口 , 否則不能被序列化//為了防止讀寫的序列化id不同,一定要指定一個固定的序列id 最好不要選擇默認的idprivate static final long serialVersionUID = 8251855228567334134L;private String name;private String password;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public static long getSerialversionuid() {return serialVersionUID;}public User(String name, String password) {super();this.name = name;this.password = password;}public User() {super();}}客戶端類
import java.io.DataInputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.net.Socket; import java.util.Scanner;import com.bjsxt.pojo.User;/*** 客戶端* */ public class Client {public static void main(String[] args) throws IOException { // 獲取Socket對象 并給定服務器地址,以及端口號Socket socket = new Socket("192.168.10.102",10000); // 獲取 對象輸出流 為了實現登錄 ,需要將登錄信息封裝成對象 參數需要一個字節流對象ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); // 創建用戶對象User user = getUser(); // 發送信息 oos.writeObject(user); // 接收響應 響應是字符串類型,所以用數據流接收 參數需要一個字節流DataInputStream dis = new DataInputStream(socket.getInputStream()); // 將響應輸出到控制臺 readUTF()方法直接返回一個String類型,可以直接輸出;System.out.println(dis.readUTF()); // 關閉流if(dis!=null) {dis.close();}if(oos!=null) {oos.close();}if(socket!=null) {socket.close();}}public static User getUser() { // 獲取鍵盤輸入對象 Scanner s = new Scanner(System.in);System.out.println("請輸入用戶名:");String username = s.next();System.out.println("請輸入密碼:");String password = s.next();return new User(username,password);}}運行效果
つづく
回首看看之前感覺很難的題目;其實也不過如此; 加油,每一個拼搏的你; 謝謝觀看; 最后會以一個小小的聊天室項目結束;敬請期待……總結
以上是生活随笔為你收集整理的小小聊天室,慢慢的回忆啊!(TCP 通信实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多线程终极模式:生产者-消费者模式
- 下一篇: 何为主宰