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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux socket ip层配置,Linux下Socket通信(TCP实现)

發(fā)布時間:2023/12/10 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux socket ip层配置,Linux下Socket通信(TCP实现) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

近期在做的項目中,涉及到了進程間數(shù)據(jù)傳輸,系統(tǒng)的原本實現(xiàn)是通過管道,但是原有的實現(xiàn)中兩個進程是在同一臺機器,而且兩個進程的關(guān)系為父子關(guān)系,而我們要做的是將其中一個進程移植到服務(wù)器上,因此兩個進程要分開,所以管道必然是不可行的方案,而對于其它的進程通信方式,FIFO,消息隊列,信號量和共享內(nèi)存,顯然也是不可行的。因此采取了通過socket的通信方式,即網(wǎng)絡(luò)套接字,用來做數(shù)據(jù)的傳輸。接下來,將對自己對socket的學(xué)習(xí)一個整理,socket是什么?socket的創(chuàng)建,綁定,發(fā)送,接收消息過程進行分析,同時附帶一個簡單的代碼實例。

網(wǎng)絡(luò)套接字Socket

套接字是通信端點的抽象,其英文socket,即為插座,孔的意思。如果兩個機子要通信,中間要通過一條線,這條線的兩端要連接通信的雙方,這條線在每一臺機子上的接入點則為socket,即為插孔,所以在通信前,我們在通信的兩端必須要建立好這個插孔,同時為了保證通信的正確,端和端之間的插孔必須要一一對應(yīng),這樣兩端便可以正確的進行通信了,而這個插孔對應(yīng)到我們實際的操作系統(tǒng)中,就是socket文件,我們再創(chuàng)建它之后,就會得到一個操作系統(tǒng)返回的對于該文件的描述符,然后應(yīng)用程序可以通過使用套接字描述符訪問套接字,向其寫入輸入,讀出數(shù)據(jù)。

站在更貼近系統(tǒng)的層級去看,兩個機器間的通信方式,無非是要通過運輸層的TCP/UDP,網(wǎng)絡(luò)層IP,因此socket本質(zhì)是編程接口(API),對TCP/UDP/IP的封裝,TCP/UDP/IP也要提供可供程序員做網(wǎng)絡(luò)開發(fā)所用的接口,這就是Socket編程接口。

Socket的創(chuàng)建

#include

int socket (int domain, int type, int protocol);

創(chuàng)建一個socket

int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

這樣,我們便創(chuàng)建了一個socket,對于socket接收的參數(shù)都有什么意義呢?從上面,我們可以知道socket是對于底層網(wǎng)絡(luò)通信的一個封裝,而對于底層的網(wǎng)絡(luò)通信也是具備多種類型的。而這些參數(shù)則是通過組合來表示各類通信的特征,從而建立正確的套接字。

domain:通信的特性,每個域有自己的地址表示格式,AF打頭,表示地址族(Address family)

type:套接字的類型,進一步確定通信特征。

protocol:表示為給定域和套接字類型選擇默認協(xié)議,當對同一域和套接字類型支持多個協(xié)議時,可以通過該字段來選擇一個特定協(xié)議,通常默認為0.上面設(shè)置的socket類型,在執(zhí)行的時候也會有默認的協(xié)議類型提供,比如SOCK_STREAM就TCP協(xié)議。

從上面的socket類型中,我們看到有SOCK_RAW該種類型,SOCK_RAW套接字提供一個數(shù)據(jù)報接口。通過這個我們可以直接訪問下面的網(wǎng)絡(luò)層,繞過TCP/UDP,因此我們可以進行制定自己的傳輸層協(xié)議。

至此,我們的socket已經(jīng)創(chuàng)建出來了,當我們不再使用的時候,我們可以調(diào)用close函數(shù)來將其關(guān)閉,釋放該文件描述符,這樣便可以得到重新的使用。

套接字通信是雙向的,但是,我們可以采用shutdown函數(shù)來禁止一個套接字的I/O.

#include

int shutdown(int sockfd, int how);

how可以用來指定讀端口或者是寫端口,這樣我們便可以關(guān)閉掉讀端或者寫端。

通信

我么已經(jīng)創(chuàng)建好了Socket,接下來要做的就是通過socket進行通信了,在兩個進程間進行通信,首先,我們要找到這些進程,找到進程,也就是能夠有這些進程的唯一標示,有了這些標示,我們才可以確定通信的雙方,然后進行數(shù)據(jù)的傳輸,對于一個通信進程的標示,所采取的方式是通過一個網(wǎng)絡(luò)地址,也就是IP地址,戰(zhàn)找到我們要通信的主機,然后通過端口號,找到相應(yīng)的服務(wù)。網(wǎng)絡(luò)地址+端口號唯一標示了一個我們要通信的目標進程。

字節(jié)序

字節(jié)序是處理器架構(gòu)的特性,用來指示像整數(shù)這種數(shù)據(jù)類型的內(nèi)部如何排序,大端和小端,因此如果通信雙方的處理器架構(gòu)不同,則會導(dǎo)致字節(jié)序的不一致的問題出現(xiàn)。最底層的網(wǎng)絡(luò)協(xié)議指定了字節(jié)序,大端字節(jié)序,但是應(yīng)用程序在處理數(shù)據(jù)時,則會遇到字節(jié)序不一致的問題。對此,系統(tǒng)提供了進行處理器字節(jié)序和網(wǎng)絡(luò)字節(jié)序之間實施轉(zhuǎn)換的函數(shù)。

#include

uint32_t htonl(uint32_t hostint32)//主機字節(jié)轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序

uint16_t htons(uint16_t hostint16)

uint32_t ntohl(uint32_t netint32)//網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)化為主機字節(jié)序

unint16_t ntohs(uint16_t netint16)

地址格式

上面,我們已經(jīng)談到如何表示一個要通信的進程,需要一個網(wǎng)絡(luò)地址和端口,而在系統(tǒng)中如何具體的標示這一特征呢?根據(jù)之前socket的創(chuàng)建,我們知道不同socket對應(yīng)了不同的通信特征,而對于不同的通信特征,其地址表示上也有一些差別。

這里我們只看一下IPV4因特網(wǎng)域地址的表示結(jié)構(gòu)。

struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr;}

sin_family: 通信的的域,這里為AF_INET

sin_port:通信的端口

sin_addr:網(wǎng)絡(luò)地址

套接字和地址關(guān)聯(lián)

我們套接字已經(jīng)創(chuàng)建好了,地址結(jié)構(gòu)也已經(jīng)了解了,接下來就是要將套接字和地址進行關(guān)聯(lián),關(guān)聯(lián)的方法則是通過bind

函數(shù)。

#include

int bind(int sockfd, const struct sockaddr *addr, socklen_t len);

創(chuàng)建地址

struct sockaddr_in server_sockaddr;server_sockaddr.sin_family = AF_INET;server_sockaddr.sin_port = htons(PORT);server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

socklen_t server_len = sizeof(server_sockaddr);

bind(server_sockfd, (struct sockaddr*)&server_sockaddr, server_len)

通過bind函數(shù),我們實現(xiàn)了socket和地址的綁定。

建立連接

socket建立好了,地址也綁定好了,這個時候,我們就可以進行連接了,要有一方進行連接的建立,通過調(diào)用connect

函數(shù)。

#include int connect(int sockfd, const struct sockaddr *addr, socklen_t len);

sockfd:這個就是本地端socket描述符,如果我們沒有賦值,系統(tǒng)會默認提供一個值。只有當服務(wù)器開啟,并正常運行,我們的連接才能夠正常建立。

如何讓socket接收連接請求呢?在另一端,我們調(diào)用listen

方法來接收連接請求。

#include int listen(int sockfd, int backlog);

sockfd:綁定了地址的socket文件描述符。

backlog:服務(wù)器負載,提示系統(tǒng)進程所要入隊的未完成請求數(shù)量。

通過listen我們得到了連接請求,接下來,就是建立連接,通過函數(shù)accept

#include

int accept(int sockfd, struct sockaddr *restric addr, socklen_t *restrict len);

調(diào)用accept函數(shù)的返回值是套接字文件描述符,該描述符連接到調(diào)用connect的客戶端。

一旦服務(wù)器調(diào)用了listen,所用的套接字就能接收連接請求,使用accept函數(shù)獲得連接請求并建立連接。

使用accept函數(shù)獲得連接請求并建立連接。

int accept(int sockfd, struct sockaddr *restrict addr, socklent_t *restrict len);

當調(diào)用accept函數(shù)會產(chǎn)生一個新的套接字,這個新的套接字和原始套接字有相同的套接類型。這個時候,我們可以傳入一個指向socket的指針和其大小,設(shè)置之后,調(diào)用了accept就會將客戶端的地址進行緩沖。

數(shù)據(jù)傳輸

連接已經(jīng)建立好了,由于socket本身都是文件描述符,因此接下來就可以調(diào)用所read和write來通過套接字通信。

對于面向連接的數(shù)據(jù)傳輸,我們需要的兩個函數(shù)是send和recv。

#include

ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags)

sockfd:accept返回的socket文件描述符。

buf:發(fā)送數(shù)據(jù),

bytes:發(fā)送數(shù)據(jù)大小

flags:對于傳送數(shù)據(jù)的一些配置項

對于不同的socket類型,系統(tǒng)提供了不同的發(fā)送方法。

#include

ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags)

具體參數(shù)和send類似。

socket選項設(shè)置

對于Socket,系統(tǒng)提供了更具體細致化的一些配置選項,通過這些配置選項,我們可以進行進一步具體的配置。

#include

int setsockopt(int sockfd, int level, int option, const void *val, socklen_t len);

sockfd:我們要進行配置的socket

level:根據(jù)我們選用的協(xié)議,配置相應(yīng)的協(xié)議編號

option:選項即為上表

最后參數(shù)是用來存放返回值

實現(xiàn)demo實例

server

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 22468

#define KEY 123

#define SIZE 1024

int main()

{

char buf[100];

memset(buf,0,100);

int server_sockfd,client_sockfd;

socklen_t server_len,client_len;

struct sockaddr_in server_sockaddr,client_sockaddr;

/*create a socket.type is AF_INET,sock_stream*/

server_sockfd = socket(AF_INET,SOCK_STREAM,0);

server_sockaddr.sin_family = AF_INET;

server_sockaddr.sin_port = htons(PORT);

server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

server_len = sizeof(server_sockaddr);

int on;

setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR,&on,sizeof(on));

/*bind a socket or rename a sockt*/

if(bind(server_sockfd, (struct sockaddr*)&server_sockaddr, server_len)==-1){

printf("bind error");

exit(1);

}

if(listen(server_sockfd, 5)==-1){

printf("listen error");

exit(1);

}

client_len = sizeof(client_sockaddr);

pid_t ppid,pid;

while(1) {

if((client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_sockaddr, &client_len)) == -1){

printf("connect error");

exit(1);

} else {

printf("create connection successfully\n");

int error = send(client_sockfd, "You have conected the server", strlen("You have conected the server"), 0);

printf("%d\n", error);

}

}

return 0;

}

client

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERVER_PORT 22468

#define MAXDATASIZE 100

#define SERVER_IP "Your IP"

int main() {

int sockfd, numbytes;

char buf[MAXDATASIZE];

struct sockaddr_in server_addr;

printf("\n======================client initialization======================\n");

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket");

exit(1);

}

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(SERVER_PORT);

server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

bzero(&(server_addr.sin_zero),sizeof(server_addr.sin_zero));

if (connect(sockfd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) == -1){

perror("connect error");

exit(1);

}

while(1) {

bzero(buf,MAXDATASIZE);

printf("\nBegin receive...\n");

if ((numbytes = recv(sockfd, buf, MAXDATASIZE, 0)) == -1){

perror("recv");

exit(1);

} else if (numbytes > 0) {

int len, bytes_sent;

buf[numbytes] = '\0';

printf("Received: %s\n",buf);

printf("Send:");

char msg[100];

scanf("%s",msg);

len = strlen(msg);

//sent to the server

if(send(sockfd, msg,len,0) == -1){

perror("send error");

}

} else {

printf("soket end!\n");

break;

}

}

close(sockfd);

return 0;

}

總結(jié)

最近也在看的一個RPC框架,thrift,定義好我們的接口文件,然后可以幫助我們生成兩端的樁文件,而且實現(xiàn)原理上,也不過是通過底層的socket通信做了包裝,執(zhí)行相應(yīng)的調(diào)用。socket通信在大三的OS課上寫過,本文主要目的記錄本次學(xué)習(xí),對于socket知識進行了一個回顧。

總結(jié)

以上是生活随笔為你收集整理的linux socket ip层配置,Linux下Socket通信(TCP实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 年下总裁被打光屁股sp | 国产精品嫩草影院av蜜臀 | 国产在线综合网 | 日批的视频 | 成人免费毛片入口 | 天天黄色片 | 中国丰满熟妇xxxx性 | 欧美日韩国产麻豆 | 蜜桃视频欧美 | 日韩黄色片 | 天天干夜夜做 | 午夜天堂精品 | 国产精品久久AV无码 | aaa在线播放 | 久操精品在线 | 欧美黑人一级片 | 国产精品99一区二区三区 | 青青草国产一区二区三区 | 快射视频网站 | 少妇又白又嫩又色又粗 | 欧美精品在线免费观看 | 亚洲精品一品 | 青青啪啪 | 男操女视频在线观看 | 国产免费内射又粗又爽密桃视频 | 动漫av网站免费观看 | 白白色在线播放 | 久久尤物视频 | 美女扒开尿口给男人桶 | 中文久久乱码一区二区 | 欧美日韩午夜精品 | 欧美日韩看片 | 一级黄片毛片 | 亚洲欲妇| 国产区在线观看 | 亚洲天堂一级 | 在线观看视频一区 | 白白色2012年最新视频 | 91理论片午午伦夜理片久久 | 欧美一区二区 | 国产毛片自拍 | 玖玖玖国产精品 | 久久精品视频一区 | 美女黄色一级视频 | 欧美亚洲第一区 | 视频一区二区免费 | 日本少妇吞精囗交 | 日本阿v视频 | 成人免费一区二区三区 | 日韩欧美黄色网址 | 成人一区二区免费视频 | 欧美系列一区二区 | 美女精品久久久 | 日韩免费高清视频网站 | 天天拍天天射 | 国产日产久久高清欧美一区 | 欧美激情视频一区二区三区在线播放 | 国产真人无遮挡作爱免费视频 | 色婷婷丁香 | 中文字幕人妻伦伦 | 欧美影视 | 亚洲欧美另类综合 | 久伊人网 | 总裁憋尿呻吟双腿大开憋尿 | 国产精品国产三级国产专区53 | 国产精品久久777777 | 欧美香蕉 | 亚洲大胆视频 | 国产自偷自拍视频 | 国产精品3p视频 | 国产成人综合在线视频 | 成人h动漫精品一区二区无码 | 东京热毛片 | 国产一卡二卡三卡四卡 | 亚洲美免无码中文字幕在线 | 欧美激情欧美激情在线五月 | 精品国产一区二区三区四区阿崩 | 国产成人8x视频一区二区 | 国产麻豆免费视频 | 韩国三级做爰高潮 | 91久久精品国产91久久性色tv | 久久精品视频一区二区三区 | 乱人伦av | 亚洲а∨天堂久久精品2021 | 国产精品日韩在线 | 国产精品1234 | 欧美日韩国产在线观看 | 亚洲美女视频一区 | 国产成人在线免费观看 | 好吊色在线观看 | 天天爱天天舔 | 亚洲人成人网 | 可以看的毛片 | 精品一区二区三区在线免费观看 | 青青导航| 久久精品国产亚洲AV黑人 | 在线观看亚洲精品 | 日韩精品免费一区二区三区 | 欧美色就是色 |