當前位置:
首頁 >
SOCKET编程-时间服务器和客户端的实现
發布時間:2025/3/15
30
豆豆
生活随笔
收集整理的這篇文章主要介紹了
SOCKET编程-时间服务器和客户端的实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- UNIX_NET
- 獲取服務器時間
- connect函數
- 獲取時間客戶端程序實現
- 獲取時間服務器實現
- 小技巧
- 宏定義的使用&&變參函數的宏定義實現
- 源碼地址
UNIX_NET
獲取服務器時間
connect函數
#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.獲取時間客戶端程序實現
#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;//< 沒有指定IP進行報錯處理if (argc != 2){UNIX_NET_DEBUG("usage: <IPaddress>\n");exit(1);}//< AF_INET 通常代表地址族協議 PF_INET 通產代表網絡協議族協議if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error!\n");}//< 將地址結構體中的數據進行清空處理bzero(&servaddr, sizeof(servaddr));//< 構造結構體servaddr.sin_family = AF_INET;servaddr.sin_port = htons(8560); // 沒有找到時間服務器使用ssh端口連接自己的電腦測試連 connect函數的實現//< 將點十進制地址轉換為網絡地址if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){perror("inet_pton error \n");}//< 使用connect創建連接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");//< 接受服務器的回復數據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的實現
#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>");//< 使用網際協議 字節流的形式創建 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地址轉換為網絡地址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");//< 使用阻塞的凡是進行read函數讀取數據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; }獲取時間服務器實現
#include "unix_net_public.h"int main(int argc, char **argv) {int listenfd, connfd;struct sockaddr_in servaddr;char buff[MAXLINE];time_t ticks;//< 創建套接字,文件描述符listenfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;//< 監聽所有的笛子, Address to accept any incoming messages. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//< 盡量使用大于8000的端口,小端口在linux上使用可能會報錯不讓使用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上測試通過,可以去github上下載對應的源碼,直接編譯
測試
$ ./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數據發送的過程剛好是三次握手,四次揮手加上一次(PSH,ACK)
抓包分析:
啟動wireshark 抓取lo網卡的網絡數據:
然后執行上述操作,對操作過程中產生的網絡數據進行抓包
整個過程經歷了三次握手和四次揮手,途中總共有7幀數據,前三幀是三次握手,后四幀是四次揮手,中間的那一次是PSH, ACK幀,是數據的發送幀
小技巧
宏定義的使用&&變參函數的宏定義實現
#define UNIX_NET_DEBUG(...) do { \printf("[%s], lien = [%d]", __FILE__, __LINE__); \printf(__VA_ARGS__); \}while(0)源碼地址
github
關注公眾號
總結
以上是生活随笔為你收集整理的SOCKET编程-时间服务器和客户端的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 作者:孙傲冰(1978-),男,博士,东
- 下一篇: 作者:洪文兴(1980-),男,厦门大学