socket入門

socket 簡介

Socket即套接字,就是對網絡中不同主機上的應用進程之間進行雙向通信的端點的抽象。一個套接字就是網絡上進程通信的一端,提供了應用層進程利用網絡協議交換數據的機制。從所處的地位來講,套接字上聯應用進程,下聯網絡協議棧,是應用程序通過網絡協議進行通信的接口。
在這里插入圖片描述
socket起源于UNIX,在Unix一切皆文件哲學的思想下,socket是一種"打開—讀/寫—關閉"模式的實現,服務器和客戶端各自維護一個"文件",在建立連接打開后,可以向自己文件寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉文件。

通信流程

socket是"打開—讀/寫—關閉"模式的實現,以使用TCP協議通訊的socket為例,其交互流程如下:
在這里插入圖片描述

TCP編程步驟:
TCP服務器端一般步驟是:
  1、創建一個socket,用函數socket();
  2、設置socket屬性,用函數setsockopt(); 可選
  3、綁定IP地址、端口等信息到socket上,用函數bind();
  4、開啟監聽,用函數listen();
  5、接收客戶端上來的連接,用函數accept();
  6、收發數據,用函數send()和recv(),或者read()和write();
  7、關閉網絡連接;
  8、關閉監聽;
TCP客戶端一般步驟是:
  1、創建一個socket,用函數socket();
  2、設置socket屬性,用函數setsockopt();可選
  3、綁定IP地址、端口等信息到socket上,用函數bind();* 可選
  4、設置要連接的對方的IP地址和端口等屬性;
  5、連接服務器,用函數connect();
  6、收發數據,用函數send()和recv(),或者read()和write();
  7、關閉網絡連接;

UDP的編程步驟:
UDP服務器端一般步驟是:
  1、創建一個socket,用函數socket();
  2、設置socket屬性,用函數setsockopt();可選
  3、綁定IP地址、端口等信息到socket上,用函數bind();
  4、循環接收數據,用函數recvfrom();
  5、關閉網絡連接;
UDP客戶端一般步驟是:
  1、創建一個socket,用函數socket();
  2、設置socket屬性,用函數setsockopt();可選
  3、綁定IP地址、端口等信息到socket上,用函數bind();可選
  4、設置對方的IP地址和端口等屬性;
  5、發送數據,用函數sendto();
  6、關閉網絡連接;

linux下socket程序示例

以TCP協議為例,實現的功能是:客戶端從服務器讀取一個字符串并打印出來。

服務器端代碼 server.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){//創建套接字int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//將套接字和IP、端口綁定struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));  //每個字節都用0填充serv_addr.sin_family = AF_INET;  //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具體的IP地址serv_addr.sin_port = htons(1234);  //端口bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//進入監聽狀態,等待用戶發起請求listen(serv_sock, 20);//接收客戶端請求struct sockaddr_in clnt_addr;socklen_t clnt_addr_size = sizeof(clnt_addr);int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//向客戶端發送數據char str[] = "Hello World!";write(clnt_sock, str, sizeof(str));//關閉套接字close(clnt_sock);close(serv_sock);return 0;
}

客戶端代碼 client.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(){//創建套接字int sock = socket(AF_INET, SOCK_STREAM, 0);//向服務器(特定的IP和端口)發起請求struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));  //每個字節都用0填充serv_addr.sin_family = AF_INET;  //使用IPv4地址serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具體的IP地址serv_addr.sin_port = htons(1234);  //端口connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//讀取服務器傳回的數據char buffer[40];read(sock, buffer, sizeof(buffer)-1);printf("Message form server: %s\n", buffer);//關閉套接字close(sock);return 0;
}

先編譯 server.cpp 并運行:

[admin@localhost ~]$ g++ server.cpp -o server
[admin@localhost ~]$ ./server

正常情況下,程序運行到 accept() 函數就會被阻塞,等待客戶端發起請求。

接下來編譯 client.cpp 并運行:

[admin@localhost ~]$ g++ client.cpp -o client
[admin@localhost ~]$ ./client
Message form server: Hello World!
[admin@localhost ~]$

client 運行后,通過 connect() 函數向 server 發起請求,處于監聽狀態的 server 被激活,執行 accept() 函數,接受客戶端的請求,然后執行 write() 函數向 client 傳回數據。client 接收到傳回的數據后,connect() 就運行結束了,然后使用 read() 將數據讀取出來。

需要注意的是:
server 只接受一次 client 請求,當 server 向 client 傳回數據后,程序就運行結束了。如果想再次接收到服務器的數據,必須再次運行 server,所以這是一個非常簡陋的 socket 程序,不能夠一直接受客戶端的請求。

源碼解析

  1. 先說一下 server.cpp 中的代碼。

第11行通過 socket() 函數創建了一個套接字,參數 AF_INET 表示使用 IPv4 地址,SOCK_STREAM 表示使用面向連接的數據傳輸方式,IPPROTO_TCP 表示使用 TCP 協議。在 Linux 中,socket 也是一種文件,有文件描述符,可以使用 write() / read() 函數進行 I/O 操作。

第19行通過 bind() 函數將套接字 serv_sock 與特定的IP地址和端口綁定,IP地址和端口都保存在 sockaddr_in 結構體中。socket() 函數確定了套接字的各種屬性,bind() 函數讓套接字與特定的IP地址和端口對應起來,這樣客戶端才能連接到該套接字。

第22行讓套接字處于被動監聽狀態。所謂被動監聽,是指套接字一直處于“睡眠”中,直到客戶端發起請求才會被“喚醒”。

第27行的 accept() 函數用來接收客戶端的請求。程序一旦執行到 accept() 就會被阻塞(暫停運行),直到客戶端發起請求。

第31行的 write() 函數用來向套接字文件中寫入數據,也就是向客戶端發送數據。

和普通文件一樣,socket 在使用完畢后也要用 close() 關閉。

  1. 再說一下 client.cpp 中的代碼。client.cpp 中的代碼和 server.cpp 中有一些區別。

第19行代碼通過 connect() 向服務器發起請求,服務器的IP地址和端口號保存在 sockaddr_in 結構體中。直到服務器傳回數據后,connect() 才運行結束。

第23行代碼通過 read() 從套接字文件中讀取數據。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444195.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444195.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444195.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode614. 二級關注者(SQL)

在 facebook 中&#xff0c;表 follow 會有 2 個字段&#xff1a; followee, follower &#xff0c;分別表示被關注者和關注者。 請寫一個 sql 查詢語句&#xff0c;對每一個關注者&#xff0c;查詢他的關注者數目。 比方說&#xff1a; ------------------------- | follow…

SPI、I2C、UART 三種串行總線對比介紹

轉載自https://blog.csdn.net/oqqHuTu12345678/article/details/65445338 參考博客 https://blog.csdn.net/xiaodingqq/article/details/80342459 https://blog.csdn.net/weiqifa0/article/details/8845281 https://www.zhihu.com/question/22632011 http://www.360doc.cn/…

leetcode1045. 買下所有產品的客戶(SQL)

Customer 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | customer_id | int | | product_key | int | ---------------------- product_key 是 Product 表的外鍵。 Product 表&#xff1a; ---------------------- | C…

Oracle利用序列實現自動增長列

在SQL Server以及MySql中都有相應的自動增長列類型,而Oracle中則沒有此類型,那如果要實現自動增長列需要怎么辦呢. 我們可以利用序列來實現.插入數據時候,可以像sql以及mysql一樣,不用顯示指定需要自動增長的列的值. 代碼實現如下: CREATE TABLE SYS_ROLES ( ID integer NOT NU…

C++ new和malloc的區別

這里先對new和delete簡單進行一下總結&#xff0c;然后再細說new和malloc的區別。 一、new和delete C語言提供了malloc和free兩個系統函數&#xff0c;完成對堆內存的申請和釋放。而C則提供了兩個關鍵字new和delete&#xff1b; 1.1 規則 new/delete是關鍵字&#xff0c;效率…

leetcode620. 有趣的電影(SQL)

某城市開了一家新的電影院&#xff0c;吸引了很多人過來看電影。該電影院特別注意用戶體驗&#xff0c;專門有個 LED顯示板做電影推薦&#xff0c;上面公布著影評和相關電影描述。 作為該電影院的信息部主管&#xff0c;您需要編寫一個 SQL查詢&#xff0c;找出所有影片描述為…

leetcode1050. 合作過至少三次的演員和導演(SQL)

ActorDirector 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | actor_id | int | | director_id | int | | timestamp | int | ---------------------- timestamp 是這張表的主鍵. 寫一條SQL查詢語句獲取合作…

linux內核相關知識

參考https://www.cnblogs.com/xdyixia/p/9248240.html linux內核啟動過程 一個嵌入式 Linux 系統從軟件角度看可以分為四個部分&#xff1a;引導加載程序&#xff08;Bootloader&#xff09;&#xff0c;Linux 內核&#xff0c;文件系統&#xff0c;應用程序。其中 Bootloade…

棧與堆的區別(內存分配與數據結構)

參考自https://blog.csdn.net/K346K346/article/details/80849966/ 堆&#xff08;Heap&#xff09;與棧&#xff08;Stack&#xff09;包含兩層含義&#xff1a; 程序內存布局場景下的內存管理方式數據結構中的兩種常見的數據結構 1. 程序內存分配中的堆與棧 1.1 棧介紹 …

leetcode10. 正則表達式匹配 一道沒有解釋的字符串dp困難題

給你一個字符串 s 和一個字符規律 p&#xff0c;請你來實現一個支持 . 和 * 的正則表達式匹配。 . 匹配任意單個字符 * 匹配零個或多個前面的那一個元素 所謂匹配&#xff0c;是要涵蓋 整個 字符串 s的&#xff0c;而不是部分字符串。 說明: s 可能為空&#xff0c;且只包含…

string相關庫函數

char *strcat(char *dest, const char *src) 功能 把 src 所指向的字符串追加到 dest 所指向的字符串的結尾。 參數&#xff1a; dest – 指向目標數組&#xff0c;該數組包含了一個 C 字符串&#xff0c;且足夠容納追加后的字符串。 src – 指向要追加的字符串&#xff0c;該…

leetcode44. 通配符匹配 又是一道沒有解釋的字符串dp困難題

給定一個字符串 (s) 和一個字符模式 (p) &#xff0c;實現一個支持 ? 和 * 的通配符匹配。 ? 可以匹配任何單個字符。 * 可以匹配任意字符串&#xff08;包括空字符串&#xff09;。 兩個字符串完全匹配才算匹配成功。 說明: s 可能為空&#xff0c;且只包含從 a-z 的小寫…

深入學習卷積神經網絡(CNN)的原理知識

轉載自https://www.cnblogs.com/wj-1314/p/9754072.html 在深度學習領域中&#xff0c;已經經過驗證的成熟算法&#xff0c;目前主要有深度卷積網絡&#xff08;DNN&#xff09;和遞歸網絡&#xff08;RNN&#xff09;&#xff0c;在圖像識別&#xff0c;視頻識別&#xff0c;語…

java中如何生成隨機數?

java中如何生成隨機數&#xff1f; package com.test.util; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; public class CharacterUtils {/*** 第一種方法&#xff1b;length為產生的位數*/public static String getRandomString(int…

leetcode132. 分割回文串 II

給定一個字符串 s&#xff0c;將 s 分割成一些子串&#xff0c;使每個子串都是回文串。 返回符合要求的最少分割次數。 示例: 輸入: "aab" 輸出: 1 解釋: 進行一次分割就可將 s 分割成 ["aa","b"] 這樣兩個回文子串。 思路&#xff1a;dp[i]…

為什么需要智能指針

參考自https://www.cnblogs.com/round1/p/12906648.html 主要為了避免以下Bug: 內存泄露 &#xff1a;對象無法被釋放&#xff0c;最常見的問題。野指針 &#xff1a; 指針指向未知。重復釋放 : 顧名思義。 &#xff08;一&#xff09;內存泄露 : 1. 拋出異常&…

leetcode1068. 產品銷售分析 I(SQL)

銷售表 Sales&#xff1a; -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- (sale_id, year) 是銷售表…

多進程與多線程通信同步機制

多進程通信方式 管道pipe&#xff1a;管道是一種半雙工的通信方式&#xff0c;數據只能單向流動&#xff0c;而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。命名管道FIFO&#xff1a;有名管道也是半雙工的通信方式&#xff0c;但是它允許無親緣關…

leetcode1069. 產品銷售分析 II(SQL)

銷售表&#xff1a;Sales -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- sale_id 是這個表的主鍵。…

leetcode1070. 產品銷售分析 III(SQL)

銷售表 Sales&#xff1a; -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- sale_id 是此表的主鍵。 …