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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UNIX网络编程笔记(2):一个简单的时间获取程序

發(fā)布時(shí)間:2023/11/30 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UNIX网络编程笔记(2):一个简单的时间获取程序 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這一講通過一個(gè)簡單的時(shí)間獲取程序簡單介紹套接字編程。

1、套接字API

1.1、套接字地址結(jié)構(gòu)

上一講中介紹了TCP的一些內(nèi)容,知道了一個(gè)套接字對唯一標(biāo)識了網(wǎng)絡(luò)中的一個(gè)TCP連接,而一個(gè)套接字標(biāo)識了一個(gè)TCP連接中的一端。套接字中包含本地IP地址和本地端口,由于現(xiàn)在的IP地址有IPv4和IPv6,因此套接字地址結(jié)構(gòu)也就有兩種。

1.1.1、IPv4套接字地址結(jié)構(gòu)

IPv4套接字地址結(jié)構(gòu)也叫“網(wǎng)際套接字地址結(jié)構(gòu)”,包含在<netinet/in.h>頭文件中,下面是它的定義:

<pre name="code" class="cpp">struct sockaddr_in {uint_8 sin_len;//地址長度sa_family_t sin_family;//協(xié)議族:在這里是AF_INETin_port_in sin_port;//16位端口號:網(wǎng)絡(luò)字節(jié)序struct in_addrsin_addr;//32位IP地址結(jié)構(gòu):網(wǎng)絡(luò)字節(jié)序char sin_zero[8];//未使用 }; struct in_addr {in_addr_t s_addr;//32位IP地址:網(wǎng)絡(luò)字節(jié)序 };

可以知道,IPv4套接字地址結(jié)構(gòu)的大小是16字節(jié)。注意:套接字地址結(jié)構(gòu)只在主機(jī)上使用,雖然一些字段(比如IP地址和端口號)可以在不同主機(jī)間傳遞,但結(jié)構(gòu)本身并不傳遞。

1.1.2、通用的套接字地址結(jié)構(gòu)

當(dāng)套接字作為參數(shù)傳遞進(jìn)套接字函數(shù)時(shí),套接字是作為引用的形式來傳遞的。下面是一個(gè)通用套接字地址結(jié)構(gòu),定義在<sys/socket.h>頭文件中:

struct sockaddr {uint8_t sa_len;//地址長度sa_family_t sa_family;//協(xié)議族char sa_data;//數(shù)據(jù):包括IP地址和端口號 };

這個(gè)結(jié)構(gòu)的唯一作用就是對指向特定于協(xié)議的套接字地址結(jié)構(gòu)的指針執(zhí)行類型強(qiáng)制轉(zhuǎn)換。

1.1.3、IPv6套接字地址結(jié)構(gòu)

IPv4套接字地址結(jié)構(gòu)也定義在<netinet/in.h>頭文件中。

struct in6_addr {uint8_t s6_addr[16];//128位IPv6地址:網(wǎng)絡(luò)字節(jié)序 };#define SIN6_LENstruct sockaddr_in6 {uint8_t sin6_len;//地址長度sa_family_t sin6_family;//協(xié)議族:在這里是AF_INET6in_port_t sin6_port;//端口號:網(wǎng)絡(luò)字節(jié)序uint32_t sin6_flowinfo;//未定義structin6_addr sin6_addr;//IPv6地址結(jié)構(gòu)uint32_t sin6_scope_id;//地址范圍 };

1.1.4、新的通用套接字地址結(jié)構(gòu)

當(dāng)需要用一個(gè)地址結(jié)構(gòu)應(yīng)用兩種不同的IP地址時(shí),這個(gè)新的通用套接字地址結(jié)構(gòu)克服了sockaddr的缺點(diǎn)。定義在<netinet/in.h>頭文件中:

struct sockaddr_storage {uint8_t ss_len;//地址長度sa_family_tss_family;//協(xié)議族 };

sockaddr_storage能夠滿足任何對齊要求;

sockaddr_storage足夠大,能容納任何一種套接字地址結(jié)構(gòu);

除了ss_len和ss_family外,其它數(shù)據(jù)對用戶透明。

1.2、值-結(jié)果參數(shù)

C 語言中,函數(shù)的返回值只能有一個(gè),不過可以通過傳遞引用參數(shù)來達(dá)到返回多個(gè)結(jié)果的效果。C++中也有按引用傳遞參數(shù),引用其實(shí)就是指針,由于實(shí)參與形參指 向同一塊地址,因此在函數(shù)中對形參的修改也會(huì)反映到實(shí)參中,這樣就達(dá)到了返回通過引用返回結(jié)果的效果。值-結(jié)果參數(shù)也是這樣。在網(wǎng)絡(luò)編程中,套接字地址結(jié) 構(gòu)通常是值-結(jié)果參數(shù)。

當(dāng)向套接字函數(shù)傳遞套接字地址結(jié)構(gòu)時(shí),總是以引用的形式來傳遞,作為參數(shù),套接字地址結(jié)構(gòu)中的地址長度告訴內(nèi)核需要從進(jìn)程中復(fù)制多少數(shù)據(jù),避免了越界訪問。如下圖:


當(dāng)函數(shù)返回時(shí),內(nèi)核將地址的真實(shí)大小放入長度中,因此長度又作為結(jié)果從內(nèi)核中返回到進(jìn)程中,告訴了進(jìn)程這個(gè)結(jié)構(gòu)究竟存儲了多少數(shù)據(jù)。這種類型的參數(shù)叫做值-結(jié)果參數(shù)。如下圖:

1.3、網(wǎng)絡(luò)字節(jié)序與主機(jī)字節(jié)序

對于多字節(jié)數(shù)據(jù),在內(nèi)存中的存數(shù)方式有兩種:小端字節(jié)序和大端字節(jié)序。

小端字節(jié)序:將低序字節(jié)存在起始地址;

大端字節(jié)序:將高序字節(jié)存在其實(shí)地址;

下圖展示了兩種格式:

舉例來說:對于數(shù)字1,小端字節(jié)序?yàn)?

0

0

0

1

A+3????????A+2????????A+1????????? A

即,0x0001

而大端字節(jié)序?yàn)?#xff1a;

1

0

0

0

A+3????????A+2????????A+1???????? A

如果不轉(zhuǎn)換的話,那么這個(gè)數(shù)就是0x1000

網(wǎng)絡(luò)字節(jié)序使用大端字節(jié)序。所以需要在主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序間轉(zhuǎn)換。下面是轉(zhuǎn)換函數(shù),定義在<netinet/in.h>頭文件中:

uint16_t htons(uint16_t host16bitvalue); uint32_t htonl(uint32_t host32bitvalue); uint16_t ntohs(uint16_t net16bitvalue); uint32_t ntohl(uint32_t net32bitvalue);

前兩個(gè)函數(shù)將主機(jī)字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序;后兩個(gè)函數(shù)將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序。

1.4、地址轉(zhuǎn)換函數(shù)

下面的函數(shù)都在<arpa/inet.h>頭文件中。
(1)inet_aton函數(shù)

函數(shù)將點(diǎn)分十進(jìn)制地址轉(zhuǎn)換成IPv4地址。定義如下:

int inet_aton(const char *strptr,struct in_addr*addrptr);

如果字符串有效就返回1,無效返回0.地址存在addrptr中,以網(wǎng)絡(luò)字節(jié)序存儲。

(2)inet_addr函數(shù)

函數(shù)將點(diǎn)分十進(jìn)制地址轉(zhuǎn)換成IPv4地址。定義如下:

in_addr_t inet_addr(const char *strptr);

如果有效返回IPv4地址,否則返回INADDR_NONE。函數(shù)已經(jīng)被廢棄。

(3)inet_ntoa函數(shù)

函數(shù)將IPv4地址轉(zhuǎn)換成點(diǎn)分十進(jìn)制地址字符串。定義如下:

cahr *inet_ntoa(struct in_addr inaddr);

參數(shù)的地址是網(wǎng)絡(luò)字節(jié)序。

以下兩個(gè)函數(shù)對IPv4和IPv6地址都適用。

(4)inet_pton函數(shù)

函數(shù)將IP地址轉(zhuǎn)換成字符串。定義如下:

int inet_pton(int family,const char *strptr,void *addrptr);如果成功返回1,輸入無效返回0,出錯(cuò)返回-1。

(5)inet_ntop函數(shù)

函數(shù)與inet_pton函數(shù)操作相反。定義如下:

const char* inet_ntop(int family,const void *addrptr,char *strptr,size_t len);如果成功返回指向結(jié)果的指針,出錯(cuò)返回NULL。

2、套接字函數(shù)

2.1、函數(shù)

套接字函數(shù)有下面幾個(gè),定義在<sys/socket.h>頭文件中。 int socket(int family,int type,int protocol);//返回:成功返回非負(fù)描述符,出錯(cuò)返回-1 int connect(int sockfd,const sockaddr *servaddr,socklen_t addrlen);//返回:成功返回0,出錯(cuò)返回-1 int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);//返回:成功返回0,出錯(cuò)返回-1 int listen(int sockfd,int backlog);//返回:成功返回0,出錯(cuò)返回-1 int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);//返回:成功返回非負(fù)描述符,出錯(cuò)返回 int close(int sockfd);//返回:成功返回0,出錯(cuò)返回

2.2、套接字函數(shù)的調(diào)用過程

下面是一個(gè)完整的TCP連接中服務(wù)器與客戶的函數(shù)調(diào)用過程:

3、一個(gè)簡單的時(shí)間獲取程序

下面的程序運(yùn)用了上面講述的內(nèi)容,分為客戶端程序和服務(wù)器端程序。代碼如下: (1)客戶端 #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 1024int main(int argc,char *argv[]) {int sockfd;char recvline[MAXLINE];if(argc!=2||strcmp(argv[1],"--help")==0){printf("Usage:%s <IPaddress>\n",argv[0]);return 0;}if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){printf("socket error\n");return 0;}struct sockaddr_in servaddr;bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(5000);if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr)<=0){printf("inet_pton error for %s\n",argv[1]);return 0;}if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0){printf("connect error\n");return 0;}int n;while((n=read(sockfd,recvline,MAXLINE))>0){recvline[n]=0;if(fputs(recvline,stdout)==EOF){printf("fputs error\n");return 0;}}if(n<0){printf("read error\n");return 0;}return 0; }(2)服務(wù)器端 #include <sys/socket.h> #include <string.h> #include <strings.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <time.h> #define MAXLINE 1024int main(int argc,char *argv[]) {int listenfd;struct sockaddr_in servaddr;char buff[MAXLINE];time_t ticks;if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0){printf("socket error\n");return 0;}bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(5000);servaddr.sin_addr.s_addr=htonl(INADDR_ANY);if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0){printf("bind error\n");return 0;}if(listen(listenfd,5)<0){printf("listen error\n");return 0;}int connfd;socklen_t len;struct sockaddr_in cliaddr;for(;;){len=sizeof(cliaddr);printf("Listening...\n");if((connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&len))<0){printf("accept error\n");return 0;}printf("Receive a connection from:%s.%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr,buff,sizeof(buff)),ntohs(cliaddr.sin_port));ticks=time(NULL);snprintf(buff,sizeof(buff),"%.24s\r\n",ctime(&ticks));if(write(connfd,buff,strlen(buff))<0){printf("write error\n");return 0;}if(close(connfd)<0){printf("close error\n");return 0;}} }運(yùn)行結(jié)果如下: (1)啟動(dòng)服務(wù)器
程序開始監(jiān)聽。 (2)啟動(dòng)客戶端
得到結(jié)果 (3)服務(wù)器端

總結(jié)

以上是生活随笔為你收集整理的UNIX网络编程笔记(2):一个简单的时间获取程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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