交互式網(wǎng)站有哪些功能友情鏈接出售
(4)本實(shí)驗(yàn)代碼的藍(lán)本,是伊圣雨老師里的課本里的代碼,略加改動(dòng)而來的。
++以下是 服務(wù)器端的代碼:
++ 每當(dāng)收到客戶端的報(bào)文時(shí),就測(cè)試一下對(duì)應(yīng)的 epoll 事件里的事件標(biāo)志,不讀取報(bào)文內(nèi)容,所以設(shè)置為 ET 邊緣觸發(fā)模式。
++ 對(duì)應(yīng)的代碼版本 :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h> //增加這倆頭文件
#include <errno.h>#define EPOLL_SIZE 50int main(int argc,char * argv[])
{ //驗(yàn)證 EPOLLHUP 等標(biāo)志的服務(wù)器端, argc = 2int serv_sock, clnt_sock, str_len, i, epfd, event_cnt;struct sockaddr_in serv_adr, clnt_adr;socklen_t adr_sz; struct epoll_event event, * ep_events;if(argc != 2) { printf("參數(shù)不是2個(gè)\n");exit(1); }serv_sock = socket(PF_INET,SOCK_STREAM,0);printf("創(chuàng)建了監(jiān)聽套接字,描述符為: %d\n",serv_sock);memset(&serv_adr,0,sizeof(serv_adr));serv_adr.sin_family = AF_INET; // 協(xié)議serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址serv_adr.sin_port = htons(atoi(argv[1])); //端口號(hào)bind( serv_sock,(struct sockaddr *)&serv_adr, sizeof(serv_adr) ) ;listen(serv_sock,5);epfd = epoll_create(EPOLL_SIZE); // EPOLL_SIZE = 50event.events = EPOLLIN; // 監(jiān)聽套接字仍為水平觸發(fā)模式event.data.fd = serv_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);ep_events = malloc(sizeof(struct epoll_event) * EPOLL_SIZE);while (1) // 此循環(huán)在正常情況下是不會(huì)退出的。{ event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1); if(-1 == event_cnt) { break; } // 出錯(cuò)則結(jié)束循環(huán),進(jìn)程退出 puts("從 epoll_wait() 返回了");//統(tǒng)計(jì)epoll_wait()的返回次數(shù)for(i = 0 ; i < event_cnt ; i++) //依次處理所有發(fā)生了事件的套接字{ if(ep_events[i].data.fd == serv_sock)//監(jiān)聽套接字{ adr_sz = sizeof(clnt_adr);clnt_sock = accept( serv_sock,(struct sockaddr *)&clnt_adr,&adr_sz );event.events = EPOLLIN | EPOLLHUP |EPOLLRDHUP | EPOLLET ;// 通信套接字用邊緣觸發(fā)是因?yàn)椴粶?zhǔn)備讀取報(bào)文event.data.fd = clnt_sock; epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event); printf("創(chuàng)建了通信套接字 id: %d\n", clnt_sock);} else { // 依次測(cè)試通訊套接字上有事件時(shí)具有的 epoll標(biāo)志。uint32_t revents = ep_events[i].events; int fd = ep_events[i].data.fd;if( revents & EPOLLIN ) printf("通信套接字 %d 上有 EPOLLIN 事件\n", fd);if( revents & EPOLLHUP ) printf("通信套接字 %d 上有 EPOLLHUP 事件\n", fd);if( revents & EPOLLRDHUP ) printf("通信套接字 %d 上有 EPOLLRDHUP 事件\n", fd);}} // for(...) } // while(...)return 0;
}
(5) 接著給出客戶端的版本,這是一個(gè) linux 版本的客戶端,很簡單的小程序:
++ 記錄其源代碼版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>int main(int argc,char * argv[])
{ // 回聲客戶端,三個(gè)參數(shù),argc = 3int sock, str_len; struct sockaddr_in serv_adr;if(argc != 3) { printf("參數(shù)不是3個(gè)\n");exit(1); }sock = socket(PF_INET,SOCK_STREAM,0);memset(&serv_adr,0,sizeof(serv_adr));serv_adr.sin_family = AF_INET;// serv_adr.sin_addr.s_addr = inet_addr(argv[1]);// inet_addr() 的語義不明,不好// 處理文本地址,只需使用 inet_pton() 與 inet_ntop() 即可。// int inet_pton(int af, const char *src, void *dst);inet_pton(AF_INET, argv[1], &serv_adr.sin_addr.s_addr);serv_adr.sin_port = htons(atoi(argv[2]));if(connect(sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) != -1)puts("客戶端套接字連接至服務(wù)器成功\n");sleep(60); // 延遲 60s 以觀察實(shí)驗(yàn)結(jié)果close(sock); // 此行可注釋,以驗(yàn)證 四次握手與 RST 報(bào)文的出現(xiàn)時(shí)機(jī)exit(0);
}
(6)后來實(shí)驗(yàn)中發(fā)現(xiàn),客戶端采用 linux 版本,會(huì)導(dǎo)致 wireshark 無法抓包,只好再編寫 windows 版本的客戶端,源代碼如下:
++ 代碼版:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>#pragma warning(disable : 4996) // 禁用關(guān)于 inet_addr 的過時(shí)警告int main()
{WSADATA m_wsadata; // 在 windows平臺(tái)使用 socket前,須做一下初始化,WSAStartup(0x0202, &m_wsadata); // 最后用 WSACleanup() 釋放庫。SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);SOCKADDR_IN server_in;memset(&server_in, 0, sizeof(SOCKADDR_IN)); //連接服務(wù)器server_in.sin_family = AF_INET;server_in.sin_port = htons(9000); // 連接至 80 端口server_in.sin_addr.s_addr = inet_addr("192.168.1.126");connect(sClient, (struct sockaddr*)&server_in, sizeof(SOCKADDR_IN));for (int i = 0; i < 1000000000; i++); // 延時(shí)一下closesocket(sClient); // 關(guān)閉套接字的函數(shù)WSACleanup(); // 用這個(gè)函數(shù)關(guān)閉庫return 0;
}
++ 使用 windows 的套接字,還要設(shè)置一下 vs2019 ,要不然上面的代碼會(huì)找不到外部函數(shù)。
++ 以及:
(7) 以下給出實(shí)驗(yàn)結(jié)果,配合 wireshark 抓包:
(8)
謝謝