日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Linux Socket基础介绍

發布時間:2023/11/27 生活经验 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux Socket基础介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux Socket函數庫是從Berkeley大學開發的BSD UNIX系統中移植過來的。BSD Socket接口是眾多Unix系統中被廣泛支持的TCP/IP通信接口,Linux下的Socket程序設計,除了微小的差別之外,也適用于大多數其它Unix系統。

Socket接口是TCP/IP網絡的API,Socket接口定義了許多函數或例程,程序員可以用它們來開發TCP/IP網絡上的應用程序。網絡的Socket數據傳輸是一種特殊的I/O,Socket也是一種文件描述符

Socket的使用和文件操作比較類似。如同文件的讀、寫、打開、關閉等操作一樣,TCP/IP網絡通信同樣也有這些操作,不過它使用的接口不是文件描述符或者FILE*,而是一個稱做Socket的描述符。類似于文件操作,對于Socket,也通過讀、寫、打開、關閉操作來進行網絡數據傳送。同時,還有一些輔助的函數,如域名/IP地址查詢、Socket功能設置等。

套接字有三種類型:流式套接字、數據報套接字及原始套接字。

流式套接字定義了一種可靠的面向連接的服務,實現了無差錯無重復的順序數據傳輸。數據報套接字定義了一種無連接的服務,數據通過相互獨立的報文進行傳輸,是無序的,并且不保證可靠、無差錯。原始套接字允許對底層協議如IP或ICMP直接訪問,主要用于新的網絡協議實現的測試等。

套接字工作過程如下服務器首先啟動,通過調用socket()建立一個套接字,然后調用bind()將該套接字和本地網絡地址聯系在一起,再調用listen()使套接字做好偵聽的準備,并規定它的請求隊列的長度,之后就調用accept()來接收連接。客戶在建立套接字后就可以調用connect()和服務器建立連接。連接一旦建立,客戶機和服務器之間就可以通過調用read()和write()來發送和接收數據。最后,待數據傳送結束后,雙方調用close()關閉套接字。

Socket函數庫

1.?socket(int domain, int type,int protocol):此函數分配一個Socket句柄,用于指定特定網絡下,使用特定的協議和數據傳送方式進行通信。Socket句柄分配以后,如果要開始TCP通信,還需要建立連接。根據需要,可以主動地建立連接(通過connect())和被動地等待對方建立連接(通過listen()),在連接建立后才能使用讀寫操作通過網絡連接進行數據交換。

domain參數選擇通信中使用的協議族,也就是網絡的類型,可以是以下之一:(1)、AF_UNIX:UNIX內部協議;(2)、AF_INET:ARPA Internet協議,也就是TCP/IP協議族;(3)、AF_ISO:ISO協議;(4)、AF_NS:Xerox Network Systems協議;(5)、AF_IMPLINK:IMP “host at IMP” link layer。

type參數為數據傳送的方式,可以是以下之一:(1)、SOCK_STREAM:保證順序的、可靠傳送的雙向字節數據流,最為常用,也是TCP連接所使用的方式;(2)、SOCK_DGRAM:無連接的、不保證可靠的、固定長度(通常很小)的消息傳送;(3)、SOCK_SEQPACKET:順序的、可靠的雙向固定長度的數據報傳送,只用于AF_NS類型的網絡中;(4)、SOCK_RAW:原始的數據傳送,適用于系統內部專用的網絡協議和接口,和SOCK_RDM一樣,只能由超級用戶使用;(5)、SOCK_RDM:可靠的數據報傳送,未實現。

protocol參數指定通信中使用的協議。在給定Socket的協議族和傳送類型之后,一般情況下所使用的協議也就固定下來,此時protocol參數可使用缺省值”0”。但如果還有多個協議供選擇,則必須使用protocol參數來標識。

socket()函數,正常執行時,返回Socket描述符;否則,返回-1,錯誤狀態在全局變量errno中。

2. close(int fd):Socket和文件描述符的關閉操作都是使用這個函數。fd參數為Socket描述符。返回值,正常是返回0,-1表示出錯。

3. bind(int sockfd, structsockaddr *my_addr, int addrlen):此函數給已經打開的Socket指定本地地址。這個函數的使用有以下兩種情況:(1)、如果此Socket是面向連接的,而且此Socket在連接建立過程中處于被動的地位,即,乙方程序使用listen函數等待對方建立連接,對方用connect函數來向此Socket建立連接,這種情況下,必須用bind給此Socket設定本地地址。在乙方使用listen函數時,除指定Socket描述符之外,該Socket必須已經用bind函數設定好了本地地址(包括IP地址和端口號),這樣,系統在收到建立連接的網絡請求時,才能根據請求的目的地址,識別是通向哪個Socket的連接,從而乙方才能用此Socket接收到發給此Socket地址的數據包。不指定Socket的本地地址,就無法將此Socket用于連接建立和數據接收。(2)、如果此Socket用于無連接的情形,同樣也要求給該Socket設定本地地址,這樣,以后系統從網絡中接收到數據后,才知道該送給哪個Socket及其相對應的進程。

sockfd參數:用于指定Socket描述符。

addrlen參數:my_addr結構的長度。

my_addr參數:用于偵聽連接請求的本地地址。struct sockaddr是一個通用性的結構,不僅包含TCP/IP協議的情況,同時也是為了適合于其它網絡,如AF_NS。由于它的這種通用性,它只是定義了一個一般意義上的存儲空間。

bind函數返回值:正常時返回0,否則返回-1,同時errno是系統錯誤碼。

4. listen(int s, int backlog):準備接收連接請求。在用bind()給一個Socket設定本地地址后,就可以將這個Socket用于接收連接請求,即listen()。調用listen()之后,系統將給此Socket配備一個連接請求的隊列,暫存系統接收到的、申請向此Socket建立連接的請求,等待用戶程序用accept()正式接收該請求。隊列長度,就由backlog參數指定。如果短時間內向乙方建立連接的請求過多,乙方來不及處理,那么排在backlog之后的請求將被系統拒絕。因此,backlog參數實際上規定了乙方程序能夠容許的連接建立處理速度。至于乙方程序使用此Socket(及其指定的本地地址)實際建立連接的個數,由乙方程序調用accept()的次數來決定。

listen函數返回值:正常時返回0,否則返回-1.

5. accept(int s, struct sockaddr*addr, int *addrlen):接受指定Socket上的連接請求。在調用listen()之后,系統就在Socket的連接請求暫存隊列里存放每一個向該Socket(及其本地地址)建立的連接請求。accept()函數的作用就是,從該暫存隊列中取出一個連接請求,用該Socket的數據,創建一個新的Socket:Socket_New,并為它分配一個文件描述符。Socket_New即標識了此次建立的連接,可被乙方用來向連接的另一方發送和接收數據(write/read, send/recv)。同時,原Socket仍然保持打開狀態不變,繼續用于等待網絡連接請求。

如果該Socket的暫存隊列中沒有待處理的連接請求,根據Socket的特征選項(是否non_blocking),blocking即阻塞,accept()函數將選擇兩種方式:如果該Socket不是non_blocking型的,accept()將一直等待,直到收到一個連接請求后才返回;如果該Socket是non_blocking型的,那么accept()將立即返回,但如果沒有連接請求,只返回錯誤信息,不創建新的Socket_New。accept()返回后,如果創建了新的Socket_New來標識新建立的連接,那么參數addr指定的結構里面將會有對方的地址信息,addrlen是地址信息的長度。

s參數:Socket描述符。

addr參數:accept()接受連接后,在addr指向的結構中存放對方的地址信息。如果是AF_INET Socket,該地址信息就是地方的IP地址和端口號。

addrlen參數:在調用accept()之前,*addrlen必須被設置為addr數據結構的合法長度。在accept()返回之后,*addrlen中是對方地址信息的長度。

accept函數返回值:如果正常創建了一個新的連接,那么返回非負的整數,即新連接的Socket描述符(注意,用于等待連接請求的原Socket保持打開狀態不變,可用于接收新的連接請求),否則,返回-1.

bind、listen、accept等函數,都是用于被動地等待對方建立連接時需要使用的,而connect函數,則是主動地向對方建立連接時使用的。connect()使用一個事先打開的Socket,和目的方(即通信對方,或稱服務器一方)地址信息,向對方發出連接建立請求。

6. connect(int sockfd, structsockaddr *serv_addr, int addrlen):客戶端發送服務請求。

sockfd參數:socket函數返回的socket描述符。

serv_addr:存儲遠程計算機的IP地址和端口信息的結構。

addrlen:是結構體sockaddr_in的長度。

返回值:成功返回0,否則返回-1.

7. send(int s, const void *msg,int len, unsigned int flags)/sendto(int s, const void *msg, int len, unsignedint flags, const struct sockaddr *to, int tolen),recv(int s, void*buf, int len, unsigned iint flags)/recvfrom(int s, void *buf, int len,unsigned int flags, struct sockaddr *from, int *fromlen):用Socket發送和接收數據。在連接建立完成后,通信雙方就可以使用以上這些函數來進行數據的發送和接收操作。其中,send和recv用于連接建立以后的發送和接收。sendto和recvfrom用于非連接的協議。對于非non_blocking型的Socket,send將等待數據發送完后才返回;對于non_blocking型的Socket,send將立即返回,用戶程序需要用select()函數決定網絡發送是否結束。類似地,對于非non_blocking型的Socket,若系統沒有收到任何數據,recv將等待接收數據到達后才返回;對于non_blocking型的Socket,recv將立即返回,并返回錯誤信息或接收到的數據字節數。sendto和recvfrom因為是非連接型的發送和接收,必須在參數中給出目的地址或者存放源地址的空間。

s參數:Socket描述符。

msg,buf參數:存放接收或者發送數據的存儲空間。

len參數:接收或者發送數據的字節數。

to,from參數:sendto和recvfrom所使用的,目的方地址和存放源地址的空間。

tolen,fromlen參數:目的地址和源地址空間大小。

flag參數:通常設為0.

返回值:send/sendto返回實際發送的數據字節數,或者-1,表示出錯。recv/recvfrom返回實際接收到的數據字節數,或者-1,表示出錯。

8. read(int fd, void *buf, size_tcount)/write(int fd, const void *buf, size_t count):用系統文件操作進行Socket通信。在連接建立完成后,對于連接建立過程中被動的一方,在accept()正常返回后,它返回一個新的Socket,并且為該Socket分配了一個文件描述符;對于連接請求發起方,connect()正常返回后,相應的Socket中也包含有已分配的文件描述符。因此,可以使用標準的Unix文件讀寫函數read()/write()來進行Socket通信。要注意的是,由于網絡數據和磁盤文件不一樣,不是已經準備好的,因此,每次讀寫操作不一定能傳送完指定長度的數據,需要由程序反復進行剩余部分的傳送。另外,文件描述符是較底層的文件操作函數,不同于C語言中常用的FILE*。FILE*是使用fread/fwrite函數來進行讀寫操作的。

fd參數:文件或者Socket描述符。

buf參數:數據緩沖區。

count參數:數據字節數。

函數返回值:正常時,返回所讀寫的字節數(注意,可能小于count參數指定的數目);否則,返回-1.

9. getsockopt(int s, int level,int optname, void *optval, int *optlen)/setsockopt(int s, int level, intoptname, const void *optval, int optlen):獲取、設置Socket特征選項。

常用的幾個轉換函數:(1)、inet_addr:將IP地址從點數格式轉換成無符號長整型,它返回的地址是網絡字節格式;(2)、inet_ntoa:將一個in_addr結構體輸出成點數格式;(3)、htonl:將32位的主機字節順序轉化為32位的網絡字節順序;(4)、htons:將16位的主機字節順序轉化為16位的網絡字節順序;(5)、ntohs:將一個無符號短整形數從網絡字節順序轉化為主機字節順序;(6)、ntohl:將一個無符號長整形數從網絡主機順序轉化為主機字節順序。

以下是測試用例:

1. test_client1.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <iostream>#define PORT 7000int main()
{struct sockaddr_in server;int s, ns;int pktlen, buflen;char buf1[256], buf2[256];s = socket(AF_INET, SOCK_STREAM, 0);server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htons(INADDR_ANY);if (connect(s, (struct sockaddr*)&server, sizeof(server)) < 0) {perror("connect()");return -1;}for (;;) {printf("Enter a line: ");std::cin>>buf1;buflen = strlen(buf1);if (buflen == 1)break;send(s, buf1, buflen+1, 0);recv(s, buf2, sizeof(buf2), 0);printf("Received line: %s\n", buf2);}close(s);return 0;
}

2. test_server1.cpp:

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>#define PORT 7000int main()
{struct sockaddr_in client, server;int s, ns, pktlen;char buf[256];s = socket(AF_INET, SOCK_STREAM, 0);memset((char*)&server, sizeof(server), 0);server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htons(INADDR_ANY);bind(s, (struct sockaddr*)&server, sizeof(server));listen(s, 1);socklen_t namelen = sizeof(client);ns = accept(s, (struct sockaddr*)&client, &namelen);for (;;) {pktlen = recv(ns, buf, sizeof(buf), 0);if (pktlen == 0)break;printf("Received line:%s\n", buf);for (int i = 0; i < strlen(buf); i++)buf[i] = toupper(buf[i]);send(ns, buf, pktlen, 0);}close(ns);close(s);return 0;
}

執行說明:(1)、打開終端,分別執行:$ g++ -o server server.cpp ?, $ g++ -o client client.cpp ; (2)、打開終端,先執行服務器端程序:$ ./server ;再打開另一終端,執行客戶端程序:$ ./client ?;(3)、程序功能:服務器端接收從客戶端來的數據,并將其接收的數據小寫字母改為大寫再發送給客戶端,在客戶端顯示接收后的結果數據。當輸入一個字符長度時退出。

注:以上部分內容整理自網絡。

GitHub:https://github.com//fengbingchun/Linux_Code_Test
?

總結

以上是生活随笔為你收集整理的Linux Socket基础介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

歡迎分享!

轉載請說明來源于"生活随笔",并保留原作者的名字。

本文地址:Linux Socket基础介绍