Socket简介及客户端服务器连接实例
注:??在客戶端游戲開發中,使用HTTP進行網絡通信的比較少,一般使用的都是Socket進行通信。而HTTP一般用于網頁或者網頁游戲。
【Socket簡介】
1、套接字(socket)概念
? ? 套接字(socket)是通信的基石,是支持TCP/IP協議的網絡通信的基本操作單元。它是網絡通信過程中端點的抽象表示,包含進行網絡通信必須的五種信息:連接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。
套接字: { IP地址 : 端口號 }
? ? 應用層通過傳輸層進行數據通信時,TCP會遇到同時為多個應用程序進程提供并發服務的問題。多個TCP連接或多個應用程序進程可能需要通過同一個TCP協議端口傳輸數據。為了區別不同的應用程序進程和連接,許多計算機操作系統為應用程序與TCP/IP協議交互提供了套接字(Socket)接口。應用層可以和傳輸層通過Socket接口,區分來自不同應用程序進程或網絡連接的通信,實現數據傳輸的并發服務。
?
2、套接字類型 ?
????TCP/IP的socket提供下列三種類型套接字。?
??2.1、流式套接字(SOCK_STREAM)
????提供了一個面向連接(TCP)、可靠的數據傳輸服務,數據無差錯、無重復地發送,且按發送順序接收。內設流量控制,避免數據流超限;數據被看作是字節流,無長度限制。文件傳送協議(FTP)即使用流式套接字。?
??2.2、數據報式套接字(SOCK_DGRAM)
????提供了一個無連接服務(UDP)。數據包以獨立包形式被發送,不提供無錯保證,數據可能丟失或重復,并且接收順序混亂。網絡文件系統(NFS)使用數據報式套接字。?
??2.3、原始式套接字(SOCK_RAW)?
????該接口允許對較低層協議,如IP、ICMP直接訪問。常用于檢驗新的協議實現或訪問現有服務中配置的新設備。
?
3、建立socket連接
? ? 建立Socket連接至少需要一對套接字,其中一個運行于客戶端,稱為ClientSocket ,另一個運行于服務器端,稱為ServerSocket 。
? ? 套接字之間的連接過程分為三個步驟:服務器監聽,客戶端請求,連接確認。
? ? (a)服務器監聽:服務器端套接字并不定位具體的客戶端套接字,而是處于等待連接的狀態,實時監控網絡狀態,等待客戶端的連接請求。
? ? (b)客戶端請求:指客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址和端口號,然后就向服務器端套接字提出連接請求。
? ? (c)連接確認:當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求時,就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,雙方就正式建立連接。而服務器端套接字繼續處于監聽狀態,繼續接收其他客戶端套接字的連接請求。
?
4、典型套接字調用過程舉例
????TCP/IP協議的應用一般采用客戶/服務器模式,因此在實際應用中,必須有客戶和服務器兩個進程,并且首先啟動服務器,其系統調用時序圖如下。?
????面向連接的協議(TCP)的套接字系統調用如下:
????????>?服務器必須首先啟動,直到它執行完accept()調用,進入等待狀態后,方能接收客戶請求。
????????>?假如客戶在此前啟動,則connect()將返回出錯代碼,連接不成功。
?
? ?無連接的協議(UDP)的套接字調用如下:
????????>?無連接服務器也必須先啟動,否則客戶請求傳不到服務進程。
????????>?無連接客戶不調用connect()。因此在數據發送之前,客戶與服務器之間尚未建立完全相關,但各自通過socket()和bind()建立了半相關。
????????>?發送數據時,發送方除指定本地套接字號外,還需指定接收方套接字號,從而在數據收發過程中動態地建立了全相關。?
?
【Socket連接】
????使用的是面向連接的TCP套接字系統調用API。
?
0、將ODSocket源碼放在Classes目錄下(ODSocket是仿照原生Socket寫的一個類似Socket的一個類)
?
1、客戶端
????使用ODSocket的API實現與服務端的網絡連接。
????????> 創建ODSocket:ODSocket?socket;
????????> 初始化:Init() 、?Create();
????????> 設置需要連接的服務器的 IP地址和端口號:ip?、?port;
????????> 連接服務器:Connet(ip, port);
????????> 發送數據:Send(string, lenght);
????????> 接收數據:Recv(string, lenght, 0);
????????> 關閉連接:Close();
????代碼如下
// 引入頭文件 #include "ODSocket/ODSocket.h"// Socker連接 void HelloWorld::connectServer() {// 初始化// ODSocket socket;socket.Init();socket.Create(AF_INET, SOCK_STREAM, 0);// 設置服務器的IP地址,端口號// 并連接服務器 Connectconst char* ip = "127.0.0.1";int port = 12345;bool result = socket.Connect(ip, port);// 發送數據 Sendsocket.Send("login", 5);if (result) {CCLOG("connect to server success!");// 開啟新線程,在子線程中,接收數據std::thread recvThread = std::thread(&HelloWorld::receiveData, this);recvThread.detach(); // 從主線程分離}else {CCLOG("can not connect to server");return;} }// 接收數據 void HelloWorld::receiveData() {// 因為是強聯網// 所以可以一直檢測服務端是否有數據傳來while (true) {// 接收數據 Recvchar data[512] = "";int result = socket.Recv(data, 512, 0);printf("%d", result);// 與服務器的連接斷開了if (result <= 0) break;CCLOG("%s", data);}// 關閉連接socket.Close(); }2、服務端
????使用Eclipse開發環境,Java語言,服務端使用的是 ServerSocket 來監聽端口。
????2.1、Server類
????用于創建ServerSocket,監聽端口,等待客戶連接。
public class Server {public static void main(String[] args) throws IOException {// 創建ServerSocket,監聽端口號:12345ServerSocket ss = new ServerSocket(12345);// 創建用于管理客戶端的收發數據的子線程類ClientThread clientThread = new ClientThread();clientThread.start();System.out.println("服務器開啟啦");// 監聽端口號:12345// 等待客戶連接 accept()while (true) {// 開始接收客戶端的連接Socket socket = ss.accept();System.out.println("有新客戶連接~");clientThread.addClient(socket);}} }2.2、ClientThread類
????用于管理、處理客戶端的收發數據請求。
// 繼承Thread線程類 public class ClientThread extends Thread {// 客戶端連接的socket列表private ArrayList<Socket> clients = new ArrayList<Socket>();// 添加客戶public void addClient(Socket socket) {clients.add(socket);}// 刪除客戶public void removeClient(Socket socket) {clients.remove(socket);}// 向客戶發送數據public void sendMessage(Socket socket, String data) throws IOException {// 給玩家發送數據OutputStream os = socket.getOutputStream();os.write(data.getBytes("UTF-8"));}@Overridepublic void run() {while (true) {try {for (Socket socket : clients) {// 獲取客戶端發來的數據InputStream is = socket.getInputStream();int len = is.available() + 1;byte[] buff = new byte[len];int flag = is.read(buff);// read()返回-1,說明客戶端的socket已斷開if (flag == -1) {System.out.println("有客戶斷開連接~");this.removeClient(socket);break;}// 輸出接收到的數據String read = new String(buff);System.out.println("收到數據:" + read);// 給玩家發送數據String data = "恭喜你,連接成功啦~~";sendMessage(socket, data);}sleep(10);} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}} } //?
總結
以上是生活随笔為你收集整理的Socket简介及客户端服务器连接实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM8获取电压值
- 下一篇: 内存如何分配和如何释放?