這一講通過乙個簡單的時間獲取程式簡單介紹套接字程式設計。
上一講中介紹了tcp的一些內容,知道了乙個套接字對唯一標識了網路中的乙個tcp連線,而乙個套接字標識了乙個tcp連線中的一端。套接字中包含本地ip位址和本地埠,由於現在的ip位址有ipv4和ipv6,因此套接字位址結構也就有兩種。
struct sockaddr_in ;
struct in_addr ;
可以知道,ipv4套接字位址結構的大小是16位元組。注意:套接字位址結構只在主機上使用,雖然一些字段(比如ip位址和埠號)可以在不同主機間傳遞,但結構本身並不傳遞。
struct sockaddr ;
這個結構的唯一作用就是對指向特定於協議的套接字位址結構的指標執行型別強制轉換。
ipv4套接字位址結構也定義在標頭檔案中。
struct in6_addr ;
#define sin6_len
struct sockaddr_in6 ;
struct sockaddr_storage ;
sockaddr_storage能夠滿足任何對齊要求;
sockaddr_storage足夠大,能容納任何一種套接字位址結構;
除了ss_len和ss_family外,其它資料對使用者透明。
c 語言中,函式的返回值只能有乙個,不過可以通過傳遞引用引數來達到返回多個結果的效果。c++中也有按引用傳遞引數,引用其實就是指標,由於實參與形参指 向同一塊位址,因此在函式中對形參的修改也會反映到實參中,這樣就達到了返回通過引用返回結果的效果。值-結果引數也是這樣。在網路程式設計中,套接字位址結 構通常是值-結果引數。
當函式返回時,核心將位址的真實大小放入長度中,因此長度又作為結果從核心中返回到程序中,告訴了程序這個結構究竟儲存了多少資料。這種型別的引數叫做值-結果引數。如下圖:
對於多位元組資料,在記憶體中的存數方式有兩種:小端位元組序和大端位元組序。
下圖展示了兩種格式:
舉例來說:對於數字1,小端位元組序為:00
01a+3 a+2 a+1 a
即,0x0001
而大端位元組序為:10
00a+3 a+2 a+1 a
如果不轉換的話,那麼這個數就是0x1000
網路位元組序使用大端位元組序。所以需要在主機位元組序和網路位元組序間轉換。下面是轉換函式,定義在標頭檔案中:
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
前兩個函式將主機位元組序轉換成網路位元組序;後兩個函式將網路位元組序轉換成主機位元組序。
下面的函式都在標頭檔案中。
(1)inet_aton函式
int inet_aton(const char *strptr,struct in_addr*addrptr);
如果字串有效就返回1,無效返回0.位址存在addrptr中,以網路位元組序儲存。
(2)inet_addr函式
in_addr_t inet_addr(const char *strptr);
如果有效返回ipv4位址,否則返回inaddr_none。函式已經被廢棄。
(3)inet_ntoa函式
cahr *inet_ntoa(struct in_addr inaddr);
引數的位址是網路位元組序。
以下兩個函式對ipv4和ipv6位址都適用。
(4)inet_pton函式
int inet_pton(int family,const char *strptr,void *addrptr);
如果成功返回1,輸入無效返回0,出錯返回-1。
(5)inet_ntop函式
函式與inet_pton函式操作相反。定義如下:
const char* inet_ntop(int family,const void *addrptr,char *strptr,size_t len);
如果成功返回指向結果的指標,出錯返回null。
套接字函式有下面幾個,定義在標頭檔案中。
int socket(int family,int type,int protocol);//返回:成功返回非負描述符,出錯返回-1
int connect(int sockfd,const sockaddr *servaddr,socklen_t addrlen);//返回:成功返回0,出錯返回-1
int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);//返回:成功返回0,出錯返回-1
int listen(int sockfd,int backlog);//返回:成功返回0,出錯返回-1
int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);//返回:成功返回非負描述符,出錯返回
int close(int sockfd);//返回:成功返回0,出錯返回
下面是乙個完整的tcp連線中伺服器與客戶的函式呼叫過程:
下面的程式運用了上面講述的內容,分為客戶端程式和伺服器端程式。**如下:
(1)客戶端
#include #include #include #include #include #include #define maxline 1024
int main(int argc,char *argv)
if((sockfd=socket(af_inet,sock_stream,0))<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)
if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
int n;
while((n=read(sockfd,recvline,maxline))>0) }
if(n<0)
return 0;
}
(2)伺服器端
#include #include #include #include #include #include #include #define maxline 1024
int main(int argc,char *argv)
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)
if(listen(listenfd,5)<0)
int connfd;
socklen_t len;
struct sockaddr_in cliaddr;
for(;;)
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)
if(close(connfd)<0)}}
執行結果如下:
(1)啟動伺服器
程式開始監聽。
(2)啟動客戶端
得到結果
(3)伺服器端
unix網路程式設計(筆記一)
一。1.乙個長時間執行的程式,即守護程序,它只在響應來自網路的請求時才傳送網路訊息。2.通常乙個客和每次只與乙個伺服器通訊,不過以web瀏覽器為例子,該客戶端程式卻可以與多個不同的web伺服器通訊。3.tcp ip 協議簇 也稱為 網際協議簇 4.英特網 和 網際網 網際網路是乙個網際網 網際網是採...
unix網路程式設計 (一)簡單概念梳理
1.2 socket 基本概念 常見結構體等 int main int argc,char argv argc 命令列總的引數的個數,即argv中元素的格式。argv 字串陣列,用來存放指向你的字串引數的指標陣列,每乙個元素指向乙個引數。argv 0 指向程式的全路徑名。argv 1 指向在dos命...
UNIX網路程式設計第乙個例子
unix網路程式設計卷1 套接字聯網api 第乙個例子編譯 可以看看相應 的網路部落格 unix網路程式設計卷1 套接字聯網api 第乙個例子編譯 不通過問題解決 看看環境程式設計 在centos中開啟daytime服務 root localhost cd etc xinetd.d root loc...