要想詳細瞭解socket,你們請自行百度,我這裏只簡單介紹。java
在網絡中,咱們能夠利用ip地址+協議+端口號惟一標示網絡中的一個進程。而socket編程就是爲了完成兩個惟一進程之間的通訊(一個是客戶端,一個是服務器端),其中用到的協議是TCP/UDP協議,它們都屬於傳輸層的協議。編程
TCP是基於鏈接的協議,在收發數據前,須要創建可靠的鏈接,也就是所謂的三次握手。使用TCP協議時,數據會準確到達,可是效率較低。服務器
UDP是面向非鏈接的協議,它不與對方創建鏈接,而是直接就把數據包發送過去。使用UDP協議時,傳輸效率高,可是不能保證數據準確到達,視頻聊天,語音聊天時就用的UDP協議。網絡
以使用TCP協議通信的socket爲例,其交互流程大概是這樣子的:socket
服務器端 客戶端ide
建立服務器端的socket 建立客戶端的socketthis
綁定端口號 鏈接服務器端的端口編碼
監聽端口 向服務器端發送數據.net
接收客戶端的鏈接請求 關閉socket線程
讀取客戶端發送數據
關閉socket
下面貼上代碼:
服務器端:
package SocketStudy;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(10068);//建立綁定到特定端口的服務器Socket。
Socket socket = null;//須要接收的客戶端Socket
int count = 0;//記錄客戶端數量
System.out.println("服務器啓動");
//定義一個死循環,不停的接收客戶端鏈接
while (true) {
socket = serverSocket.accept();//偵聽並接受到此套接字的鏈接
InetAddress inetAddress=socket.getInetAddress();//獲取客戶端的鏈接
ServerThread thread=new ServerThread(socket,inetAddress);//本身建立的線程類
thread.start();//啓動線程
count++;//若是正確創建鏈接
System.out.println("客戶端數量:" + count);//打印客戶端數量
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
自定義線程類:
package SocketStudy;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class ServerThread extends Thread {
Socket socket = null;
InetAddress inetAddress=null;//接收客戶端的鏈接
public ServerThread(Socket socket,InetAddress inetAddress) {
this.socket = socket;
this.inetAddress=inetAddress;
}
@Override
public void run() {
InputStream inputStream = null;//字節輸入流
InputStreamReader inputStreamReader = null;//將一個字節流中的字節解碼成字符
BufferedReader bufferedReader = null;//爲輸入流添加緩衝
OutputStream outputStream = null;//字節輸出流
OutputStreamWriter writer = null;//將寫入的字符編碼成字節後寫入一個字節流
try {
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
bufferedReader = new BufferedReader(inputStreamReader);
String info = null;//臨時
//循環讀取客戶端信息
while ((info = bufferedReader.readLine()) != null) {
//獲取客戶端的ip地址及發送數據
System.out.println("服務器端接收:"+"{'from_client':'"+socket.getInetAddress().getHostAddress()+"','data':'"+info+"'}");
}
socket.shutdownInput();//關閉輸入流
//響應客戶端請求
outputStream = socket.getOutputStream();
writer = new OutputStreamWriter(outputStream, "UTF-8");
writer.write("{'to_client':'"+inetAddress.getHostAddress()+"','data':'我是服務器數據'}");
writer.flush();//清空緩衝區數據
} catch (IOException e) {
e.printStackTrace();
} finally {
//關閉資源
try {
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客戶端:
package SocketStudy;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class SocketClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("服務器的ip", 10068);
OutputStream outputStream = socket.getOutputStream();//獲得一個輸出流,用於向服務器發送數據
OutputStreamWriter writer=new OutputStreamWriter(outputStream,"UTF-8");//將寫入的字符編碼成字節後寫入一個字節流
System.out.println("請輸入數據:");
Scanner sc = new Scanner(System.in);
String data = sc.nextLine();
writer.write(data);
writer.flush();//刷新緩衝
socket.shutdownOutput();//只關閉輸出流而不關閉鏈接
//獲取服務器端的響應數據
InputStream inputStream = socket.getInputStream();//獲得一個輸入流,用於接收服務器響應的數據
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");//將一個字節流中的字節解碼成字符
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);//爲輸入流添加緩衝
String info = null;
System.out.println("客戶端IP地址:"+socket.getInetAddress().getHostAddress());
//輸出服務器端響應數據
while ((info = bufferedReader.readLine()) != null) {
System.out.println("客戶端接收:" + info);
}
//關閉資源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
writer.close();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行結果(先運行服務器端,再運行客戶端):
服務器:
客戶端:
回車以後
客戶端:
服務器端:
在cmd下運行(先編譯再運行生成的.class文件,若是有中文,須要加encoding參數,當類中有導入本身建立的類時,須要切換到能包含該類的文件夾下執行命令,不然會報錯)
此時的服務器端: