關(guān)于Socket的解析以及雙方即時通訊的java實現(xiàn)方法
在Java編程之中,我們通常都會接觸到網(wǎng)絡(luò)編程,那么不可避免地就會接觸到Socket通信,下面我將對Socket進行簡單的解析,并給出雙方通訊的代碼實現(xiàn)方案
首先我們來介紹一下整個Socket的通信過程

首先服務(wù)端先創(chuàng)建一個SocketServer,那么創(chuàng)建一個SocketServer需要我們指定端口號,如下
ServerSocket serverSocket=new ServerSocket(8888);
像上面這樣我們就簡單的開了一個端口號為8888的ServerSocket了
接下來我們需要去接收來自客戶端的連接請求,也就是圖中的Other Socket,我們可以利用SockerServer的accept方法來建立連接,并且這個方法會返回一個Socket,用于和Other Socker進行通信,簡單來說,我們就是利用SockerServer來獲取Socket,然后利用這個Socket和別人通信
接下來我們獲取Socket的輸入輸出流,實現(xiàn)發(fā)送和接收信息,到此,我們已經(jīng)知道兩方進行Socket通信的基本思路了
接下來我們來看看關(guān)于ServerSocket以及Socket的一些關(guān)鍵方法
ServerSocket
首先我們看一下ServerSocket的構(gòu)造方法,一共有4種:
1、無參的構(gòu)造方法 :
ServerSocket(), 返回沒有綁定端口號的ServerSocket實例
2、含一個參數(shù)的構(gòu)造方法 :
ServerSocket(int port),返回綁定給定端口號的ServerSocket實例
3、含兩個參數(shù)的構(gòu)造方法 :
ServerSocket(int port, int backlog),返回綁定給定端口號的ServerSocket實例,并且設(shè)定同步隊列(syns queue)的大小
4、含三個參數(shù)的構(gòu)造方法:
ServerSocket(int port, int backlog, InetAddress bindAddr),返回綁定給定端口號的ServerSocket實例,并且設(shè)定同步隊列(syns queue)的大小以及綁定給定的IP地址
主要看它的一些方法:
accept()
這個方法監(jiān)聽連接,一旦連接就返回一個Socket用于通信,需要注意的是,該方法為阻塞方法,如果沒有連接程序并不會繼續(xù)執(zhí)行下去
close()
關(guān)閉Socket,如果accept還在阻塞的話,就會拋出一個SocketException的異常
關(guān)于ServerSocket就不多加贅述了,我們來看一看Socket
Socket
構(gòu)造方法依然存在多種,這里只給出一個較為典型的
Socket(String host, int port),第一個參數(shù)是主機的IP地址作為字符串傳入,第二個參數(shù)為端口號
getInputStream(), getOutputStream()
獲得Socket的輸入輸出流,我們可以利用BufferReader以及PrintWriter來對這兩個流進行操作,如下:
BufferReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream()));
下面簡單編寫一個雙方互相通信的java實現(xiàn)
首先是服務(wù)端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* Created by Mezereon on 2017/3/1.
*/
public class TCPServer {
private Socket socket;
private ServerSocket serverSocket;
private BufferedReader reader;
private PrintWriter writer;
private Scanner scanner = new Scanner(System.in);
//開啟服務(wù)
public void run() throws IOException {
startTheSocket();
}
public void startTheSocket() throws IOException {
serverSocket=new ServerSocket(18080); //打開18080端口等待連接
acceptTheSocket();//接受連接并且初始化Socket,reader,writer
openTheNewThreadToGetMessageFromClient();
while(true) {
getYourMessage();//獲取鍵盤數(shù)據(jù)并作為輸入
}
}
//接受連接并且初始化Socket,reader,writer
private void acceptTheSocket() throws IOException {
socket=serverSocket.accept();//阻塞方法,用于接受Socket連接
System.out.println("Some one connect me ,it is "+socket.getLocalSocketAddress());//打印地址
System.out.println("It's port is "+socket.getPort());//打印端口號
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//獲得輸入流
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));//獲得輸出流
}
//掃描鍵盤并輸入數(shù)據(jù)
private void getYourMessage() throws IOException {
String yourMessage = scanner.nextLine();
checkYourMessage(yourMessage);//檢查發(fā)送給客戶端的信息
writer.println(yourMessage);//發(fā)送信息
writer.flush();//flush方法用于清空緩沖區(qū),注意的是如果不flush你的信息可能發(fā)不出去一直存留在緩沖區(qū)
}
//用于檢查是否退出
private void checkYourMessage(String yourMessage) throws IOException {
//關(guān)閉各種
if (yourMessage.equals("exit")) {
socket.close();
writer.close();
reader.close();
System.exit(0);
}
}
//開啟一個新的線程來監(jiān)聽客戶端發(fā)來的信息
private void openTheNewThreadToGetMessageFromClient() throws IOException {
//開啟一個新的線程
new Thread(new Runnable() {
@Override
public void run() {
getTheMessageFromClient();
}
}).start();
}
//不斷循環(huán)來獲取客戶端發(fā)來的信息
private void getTheMessageFromClient() {
while(true) {
String messageFromClient = null;
try {
messageFromClient = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
printTheMessage(messageFromClient);//打印客戶端發(fā)來的信息
}
}
//打印客戶端發(fā)來的信息
private void printTheMessage(String messageFromClient) {
if(messageFromClient!=null)
System.out.println("He say:"+messageFromClient);
}
}
然后開始編寫客戶端:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
/**
* Created by Mezereon on 2017/2/27.
*/
public class TCPClient {
private Socket socket;
private BufferedReader reader ;
private PrintWriter writer;
private Scanner scanner = new Scanner(System.in);
//開啟Socket來連接
public void run() throws IOException{
startTheSocket();
}
//開始連接服務(wù)端
private void startTheSocket() throws IOException{
toConnectTheServer();//創(chuàng)建Socket并初始化
openTheThreadToReceiveInfoFromServer();//開啟一個新的線程來接受服務(wù)端發(fā)來的信息
//一個循環(huán),用于讀取鍵盤的輸入
while(true) {
String yourMessage = scanner.nextLine();
//不為空則發(fā)送信息
if(yourMessage!=null) {
writer.println(yourMessage);
writer.flush();//記得flush清空緩沖區(qū)
}
//判斷是否退出
if (yourMessage.equals("exit")) {
disConnect();
System.exit(0);
}
}
}
//創(chuàng)建一個Socket來連接本機的18080端口的服務(wù)端并初始化reader和writer
private void toConnectTheServer() throws IOException {
socket=new Socket("127.0.0.1",18080);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
}
private void openTheThreadToReceiveInfoFromServer() throws IOException {
new Thread(new Runnable() {
@Override
public void run() {
try {
printMessage();//打印從服務(wù)端收到的信息
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
//循環(huán)不斷讀取服務(wù)端的信息
private void printMessage() throws IOException {
while (true) {
String messageFromServer = null;
try {
messageFromServer = reader.readLine();//讀取信息
System.out.println("He say:" + messageFromServer);//打印信息
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
}
if(messageFromServer.equals("exit")){
disConnect();//關(guān)閉連接
System.exit(0);
}
}
}
//關(guān)閉各種
private void disConnect() throws IOException {
socket.close();
reader.close();
writer.close();
}
}
至此,關(guān)于Socket通信簡單的介紹以及利用java進行簡單的通信的實現(xiàn)就結(jié)束了~
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解大數(shù)據(jù)處理引擎Flink內(nèi)存管理
Flink是jvm之上的大數(shù)據(jù)處理引擎,jvm存在java對象存儲密度低、full gc時消耗性能,gc存在stw的問題,同時omm時會影響穩(wěn)定性。針對頻繁序列化和反序列化問題flink使用堆內(nèi)堆外內(nèi)存可以直接在一些場景下操作二進制數(shù)據(jù),減少序列化反序列化消耗。本文帶你詳細理解其原理。2021-05-05
多數(shù)據(jù)源模式JPA整合sharding-jdbc實現(xiàn)數(shù)據(jù)脫敏
這篇文章主要為大家介紹了JPA項目中多數(shù)據(jù)源模式整合sharding-jdbc來實現(xiàn)數(shù)據(jù)脫敏,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02
使用Spring MVC攔截器實現(xiàn)日志記錄的方法
本篇文章主要介紹了使用Spring MVC攔截器實現(xiàn)日志記錄的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
MyBatisPlus代碼生成器的原理及實現(xiàn)詳解
這篇文章主要為大家詳細介紹了MyBatisPlus中代碼生成器的原理及實現(xiàn),文中的示例代碼講解詳細,對我們學習MyBatisPlus有一定幫助,需要的可以參考一下2022-08-08
Java創(chuàng)建線程的七種方法總結(jié)(全網(wǎng)最全面)
線程是Java中的基本執(zhí)行單元,它允許程序在同一時間執(zhí)行多個任務(wù),下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java創(chuàng)建線程的七種方法,文中通過實例代碼將這七種方法介紹的非常詳細,需要的朋友可以參考下2023-05-05
SpringBoot使用Thymeleaf自定義標簽的實例代碼
這篇文章主要介紹了SpringBoot使用Thymeleaf自定義標簽的實例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09

