SOCKET编程-时间服务器和客户端的实现
生活随笔
收集整理的這篇文章主要介紹了
SOCKET编程-时间服务器和客户端的实现
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
文章目錄
- UNIX_NET
- 獲取服務(wù)器時(shí)間
- connect函數(shù)
- 獲取時(shí)間客戶端程序?qū)崿F(xiàn)
- 獲取時(shí)間服務(wù)器實(shí)現(xiàn)
- 小技巧
- 宏定義的使用&&變參函數(shù)的宏定義實(shí)現(xiàn)
- 源碼地址
UNIX_NET
獲取服務(wù)器時(shí)間
connect函數(shù)
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);DESCRIPTIONThe connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. The addrlen argument specifies the size of addr. The format of the address in addr is determined by the address space of the socket sockfd; see socket(2) for fur‐ther details.If the socket sockfd is of type SOCK_DGRAM, then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received. If the socket is of type SOCK_STREAM or SOCK_SEQPACKET, this call attempts to make a connection to the socket that is bound to the address specified by addr.Generally, connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use connect() multiple times to change their association. Connectionless sockets may dissolve the association by connecting to an address with the sa_family member of sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2).RETURN VALUEIf the connection or binding succeeds, zero is returned. On error, -1 is returned, and errno is set appropriately.獲取時(shí)間客戶端程序?qū)崿F(xiàn)
#include "unix_net_public.h" #include <stdio.h> #include <strings.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <errno.h> #include <unistd.h> #include <stdlib.h>#define MAXLINE 4096int main(int argc, char *argv[]) {int sockfd, n;char recvline[MAXLINE + 1];struct sockaddr_in servaddr;//< 沒(méi)有指定IP進(jìn)行報(bào)錯(cuò)處理if (argc != 2){UNIX_NET_DEBUG("usage: <IPaddress>\n");exit(1);}//< AF_INET 通常代表地址族協(xié)議 PF_INET 通產(chǎn)代表網(wǎng)絡(luò)協(xié)議族協(xié)議if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error!\n");}//< 將地址結(jié)構(gòu)體中的數(shù)據(jù)進(jìn)行清空處理bzero(&servaddr, sizeof(servaddr));//< 構(gòu)造結(jié)構(gòu)體servaddr.sin_family = AF_INET;servaddr.sin_port = htons(8560); // 沒(méi)有找到時(shí)間服務(wù)器使用ssh端口連接自己的電腦測(cè)試連 connect函數(shù)的實(shí)現(xiàn)//< 將點(diǎn)十進(jìn)制地址轉(zhuǎn)換為網(wǎng)絡(luò)地址if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){perror("inet_pton error \n");}//< 使用connect創(chuàng)建連接UNIX_NET_DEBUG("connect start\n");if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){perror("connect error\n");}UNIX_NET_DEBUG("connect is end !\n");//< 接受服務(wù)器的回復(fù)數(shù)據(jù)while((n = read(sockfd, recvline, MAXLINE)) > 0){recvline[n] = 0;if(fputs(recvline, stdout) == EOF){perror("fputs error\n");}}if (n < 0){perror("error exit()");}return 0; }支持IPv6的實(shí)現(xiàn)
#include "unix_net_public.h"int main(int argc, char **argv) {int sockfd, n;struct sockaddr_in6 servaddr;char recvline[MAXLINE + 1];if (argc != 2)UNIX_NET_DEBUG("usage: a.out <IPaddress>");//< 使用網(wǎng)際協(xié)議 字節(jié)流的形式創(chuàng)建 socket句柄if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)UNIX_NET_DEBUG("socket error");bzero(&servaddr, sizeof(servaddr));servaddr.sin6_family = AF_INET6;servaddr.sin6_port = htons(8560); /* daytime server *///< 將IP地址轉(zhuǎn)換為網(wǎng)絡(luò)地址if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)UNIX_NET_DEBUG("inet_pton error for %s", argv[1]);if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)UNIX_NET_DEBUG("connect error");//< 使用阻塞的凡是進(jìn)行read函數(shù)讀取數(shù)據(jù)while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {recvline[n] = 0; /* null terminate */if (fputs(recvline, stdout) == EOF)UNIX_NET_DEBUG("fputs error");}if (n < 0)UNIX_NET_DEBUG("read error");return 0; }獲取時(shí)間服務(wù)器實(shí)現(xiàn)
#include "unix_net_public.h"int main(int argc, char **argv) {int listenfd, connfd;struct sockaddr_in servaddr;char buff[MAXLINE];time_t ticks;//< 創(chuàng)建套接字,文件描述符listenfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;//< 監(jiān)聽(tīng)所有的笛子, Address to accept any incoming messages. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//< 盡量使用大于8000的端口,小端口在linux上使用可能會(huì)報(bào)錯(cuò)不讓使用servaddr.sin_port = htons(8560); /* daytime server *///< 綁定套接字bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));listen(listenfd, LISTENQ);for ( ; ; ) {connfd = accept(listenfd, (struct sockaddr *) NULL, NULL);ticks = time(NULL);snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));write(connfd, buff, strlen(buff));close(connfd);} }以上代碼全部在UBUNTU 16.04上測(cè)試通過(guò),可以去github上下載對(duì)應(yīng)的源碼,直接編譯
測(cè)試
$ ./putdaytimesrv & [1] 2952 $ ./getdaytimetcpclient 127.0.0.1 [getdaytimetcpclient.c], lien = [47]connect start [getdaytimetcpclient.c], lien = [52]connect is end ! Sun Jul 14 14:57:22 2019數(shù)據(jù)發(fā)送的過(guò)程剛好是三次握手,四次揮手加上一次(PSH,ACK)
抓包分析:
啟動(dòng)wireshark 抓取lo網(wǎng)卡的網(wǎng)絡(luò)數(shù)據(jù):
然后執(zhí)行上述操作,對(duì)操作過(guò)程中產(chǎn)生的網(wǎng)絡(luò)數(shù)據(jù)進(jìn)行抓包
整個(gè)過(guò)程經(jīng)歷了三次握手和四次揮手,途中總共有7幀數(shù)據(jù),前三幀是三次握手,后四幀是四次揮手,中間的那一次是PSH, ACK幀,是數(shù)據(jù)的發(fā)送幀
小技巧
宏定義的使用&&變參函數(shù)的宏定義實(shí)現(xiàn)
#define UNIX_NET_DEBUG(...) do { \printf("[%s], lien = [%d]", __FILE__, __LINE__); \printf(__VA_ARGS__); \}while(0)源碼地址
github
關(guān)注公眾號(hào)
總結(jié)
以上是生活随笔為你收集整理的SOCKET编程-时间服务器和客户端的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 作者:孙傲冰(1978-),男,博士,东
- 下一篇: 作者:洪文兴(1980-),男,厦门大学