1、關於字節排序 網際協議採用大端字節序,來傳輸多字節整數。 系統提供了轉換的宏定義,如果主機與網際協議相同,則宏定義爲空。
2、客戶端 socket -> connect(阻塞,三次握手)-> rcv
3、服務器端 socket -> bind -> listen -> accept(阻塞,三次握手)-> send4、函數介紹
a..socket
1)函數原型 int socket(int family, int type, int protocol)
2)參數: family: 協議族AF_INET,IPv4協議 ... type : type 套接字類型SOCK_STREAM 字節流套接字 protocol: IPPROCO_TCP IPPROCO_UDP IPPROCO_SCTP
3)返回值 成功:返回套接字符 錯誤:返回INVALID_SOCKET(-1)
4)示例
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- int main()
- {
- int socketfd;
- struct sockaddr_in servaddr;
- if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- return -1;
- }
- }
b..connect
1)函數原型 int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
2)參數:
sockfd: socket 函數返回的套接字描述符
servaddr : 服務器的IP和端口
addrlen: 長度(sizeof(servaddr))
3)返回值
成功:0
錯誤:返回INVALID_SOCKET(-1)
4)示例
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- int main()
- {
- int socketfd;
- struct sockaddr_in servaddr;
- if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- printf("socket error\n");
- return -1;
- }
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_addr.s_addr = inet_addr("192.168.0.218");
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(55000);
- if(connect(socketfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
- {
- printf("connect error\n");
- }
- return 0;
- }
c..bind
1)函數原型 int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
2)參數:
sockfd: socket 函數返回的套接字描述符
servaddr : 服務器的IP和端口
addrlen: 長度(sizeof(servaddr))
3)返回值
成功:0
錯誤:返回INVALID_SOCKET(-1)
d..listen
1)函數原型 int listen(int sockfd, int backlog)
2)參數:
sockfd: socket 函數返回的套接字描述符
backlog : 內核中套接字排隊的最大個數
3)返回值
成功:0
錯誤:返回INVALID_SOCKET
e..accept
1)函數原型 int accept(int sockfd, const struct sockaddr *servaddr, socklen_t *addrlen)
2)參數:
sockfd: socket 函數返回的套接字描述符
3)返回值
servaddr : 客戶進程的IP和端口(可設爲null)
addrlen: 長度(sizeof(servaddr))(可設爲null)
成功:從監聽套接字返回已連接套接字
錯誤:
如果對客戶信息不感興趣,後兩個參數可以置空。
4)示例
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- int main()
- {
- int count = 0;
- int listenfd, socketfd;
- int nread;
- struct sockaddr_in servaddr;
- struct timeval timeoutval;
- char readbuf[256];
- printf("accept started\n");
- //socket
- if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- printf("socket error\n");
- return -1;
- }
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(59000);
- //bind
- if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
- {
- printf("bind error\n");
- //return -1;
- }
- //listen
- listen(listenfd, 5);
- //accept
- socketfd = accept(listenfd, NULL, NULL);
- while(1)
- {
- printf("start receive %d...\n", count++);
- memset(readbuf, sizeof(readbuf), 0);
- nread = recv(socketfd, readbuf, 10, 0);
- if(nread>0)
- {
- readbuf[10] = '\0';
- printf("receiveed %s, nread = %d\n\n", readbuf, nread);
- }
- }
- return 0;
- }
/**************************************************************
從 I/O 事件分派機制來看,使用 select()是不合適的,因爲它所支持的併發連接數有限(通
常在 1024 個以內)。如果考慮性能,poll()也是不合適的,儘管它可以支持的較高的 TCP 併發
數,但是由於其採用“輪詢”機制,當併發數較高時,其運行效率相當低,並可能存在 I/O 事
件分派不均,導致部分 TCP 連接上的 I/O 出現“飢餓”現象。而如果使用 epoll 或 AIO,則沒
有上述問題(早期 Linux 內核的 AIO 技術實現是通過在內核中爲每個 I/O 請求創建一個線程來
實現的,這種實現機制在高併發 TCP 連接的情形下使用其實也有嚴重的性能問題。但在最新的
Linux 內核中,AIO 的實現已經得到改進)。
支持一個進程打開大數目的 socket 描述符(FD)select 最不能忍受的是一個進程所打開的
FD 是有一定限制的,由 FD_SETSIZE 設置,默認值是 2048。對於那些需要支持的上萬連接數目
的 IM 服務器來說顯然太少了。
這時候你一是可以選擇修改這個宏然後重新編譯內核,不過資料
也同時指出這樣會帶來網絡效率的下降,二是可以選擇多進程的解決方案(傳統的 Apache 方
案),不過雖然 linux 上面創建進程的代價比較小,但仍舊是不可忽視的,加上進程間數據同步
遠比不上線程間同步的高效,所以也不是一種完美的方案。不過 epoll 則沒有這個限制,它所
支持的 FD 上限是最大可以打開文件的數目,這個數字一般遠大於 2048,舉個例子,在 1GB 內存
的機器上大約是 10 萬左右,具體數目可以 cat /proc/sys/fs/file-max 察看,一般來說這個數
目和系統內存關係很大。
******************************************************************/
5. select函數
1)函數原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
2)參數:
sockfd: socket 函數返回的套接字描述符
readfds : 讀描述符集合
writefds: 寫描述符集合
errorfds: 錯誤描述符集合
timeout: 超時
3)返回值
成功:返回值 0:無 >0:描述符就緒的總位數
錯誤:返回INVALID_SOCKET(-1)
4)包含頭文件: include <sys/select.h> include <sys/time.h>
5)示例
- /* 實現功能:通過select處理多個socket
- * 監聽一個端口,監聽到有鏈接時,添加到select的w.
- */
- #include "select.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr; /* client's address information */
- } CLIENT;
- #define MYPORT 59000
- //最多處理的connect
- #define BACKLOG 5
- //最多處理的connect
- CLIENT client[BACKLOG];
- //當前的連接數
- int currentClient = 0;
- //數據接受 buf
- #define REVLEN 10
- char recvBuf[REVLEN];
- //顯示當前的connection
- void showClient();
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- struct timeval timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
- for(i=0; i<BACKLOG; i++)
- {
- client[i].fd = -1;
- }
- //socket
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- //bind
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
- //listen
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
- for(i=0; i<BACKLOG; i++)
- {
- client[i].fd = -1;
- }
- //select
- while(1)
- {
- FD_ZERO(&readfds);
- FD_SET(sockListen, &readfds);
- sockMax = sockListen;
- //加入client
- for(i=0; i<BACKLOG; i++)
- {
- if(client[i].fd >0)
- {
- FD_SET(client[i].fd, &readfds);
- if(sockMax<client[i].fd)
- sockMax = client[i].fd;
- }
- }
- timeout.tv_sec=3;
- timeout.tv_usec=0;
- //select
- ret = select((int)sockMax+1, &readfds, NULL, NULL, &timeout);
- if(ret < 0)
- {
- printf("select error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
- printf("test111\n");
- //讀取數據
- for(i=0; i<BACKLOG; i++)
- {
- if(client[i].fd>0 && FD_ISSET(client[i].fd, &readfds))
- {
- if(recvLen != REVLEN)
- {
- while(1)
- {
- //recv數據
- ret = recv(client[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- client[i].fd = -1;
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- client[i].fd = -1;
- recvLen = 0;
- break;
- }
- //數據接受正常
- recvLen = recvLen+ret;
- if(recvLen<REVLEN)
- {
- continue;
- }
- else
- {
- //數據接受完畢
- printf("%s, buf = %s\n", inet_ntoa(client[i].addr.sin_addr) , recvBuf);
- //close(client[i].fd);
- //client[i].fd = -1;
- recvLen = 0;
- break;
- }
- }
- }
- }
- }
- //如果可讀
- if(FD_ISSET(sockListen, &readfds))
- {
- printf("isset\n");
- sockSvr = accept(sockListen, NULL, NULL);//(struct sockaddr*)&client_addr
- if(sockSvr == -1)
- {
- printf("accpet error\n");
- }
- else
- {
- currentClient++;
- }
- for(i=0; i<BACKLOG; i++)
- {
- if(client[i].fd < 0)
- {
- client[i].fd = sockSvr;
- client[i].addr = client_addr;
- printf("You got a connection from %s \n",inet_ntoa(client[i].addr.sin_addr) );
- break;
- }
- }
- //close(sockListen);
- }
- }
- printf("test\n");
- return 0;
- }
- //顯示當前的connection
- void showClient()
- {
- int i;
- printf("client count = %d\n", currentClient);
- for(i=0; i<BACKLOG; i++)
- {
- printf("[%d] = %d", i, client[i].fd);
- }
- printf("\n");
- }
6. poll函數
1)函數原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
2)參數:
sockfd: socket 函數返回的套接字描述符
readfds : 讀描述符集合
writefds: 寫描述符集合
errorfds: 錯誤描述符集合
timeout: 超時
3)返回值
成功:返回值 0:無 >0:描述符就緒的總位數
錯誤:返回INVALID_SOCKET(-1)
4)包含頭文件: include <sys/select.h> include <sys/time.h>
5) 示例
- /* 實現功能:通過poll, 處理多個socket
- * 監聽一個端口,監聽到有鏈接時,添加到poll.
- */
- #include "select.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <poll.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr; /* client's address information */
- } CLIENT;
- #define MYPORT 59000
- //最多處理的connect
- #define BACKLOG 5
- //當前的連接數
- int currentClient = 0;
- //數據接受 buf
- #define REVLEN 10
- char recvBuf[REVLEN];
- #define OPEN_MAX 1024
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- int timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
- struct pollfd clientfd[OPEN_MAX];
- //socket
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- //bind
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
- //listen
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
- //clientfd 初始化
- clientfd[0].fd = sockListen;
- clientfd[0].events = POLLIN; //POLLRDNORM;
- sockMax = 0;
- for(i=1; i<OPEN_MAX; i++)
- {
- clientfd[i].fd = -1;
- }
- //select
- while(1)
- {
- timeout=3000;
- //select
- ret = poll(clientfd, sockMax+1, timeout);
- if(ret < 0)
- {
- printf("select error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
- if (clientfd[0].revents & POLLIN)//POLLRDNORM
- {
- sockSvr = accept(sockListen, NULL, NULL);//(struct sockaddr*)&client_addr
- if(sockSvr == -1)
- {
- printf("accpet error\n");
- }
- else
- {
- currentClient++;
- }
- for(i=0; i<OPEN_MAX; i++)
- {
- if(clientfd[i].fd<0)
- {
- clientfd[i].fd = sockSvr;
- break;
- }
- }
- if(i==OPEN_MAX)
- {
- printf("too many connects\n");
- return -1;
- }
- clientfd[i].events = POLLIN;//POLLRDNORM;
- if(i>sockMax)
- sockMax = i;
- }
- //讀取數據
- for(i=1; i<=sockMax; i++)
- {
- if(clientfd[i].fd < 0)
- continue;
- if (clientfd[i].revents & (POLLIN | POLLERR))//POLLRDNORM
- {
- if(recvLen != REVLEN)
- {
- while(1)
- {
- //recv數據
- ret = recv(clientfd[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- clientfd[i].fd = -1;
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- clientfd[i].fd = -1;
- recvLen = 0;
- break;
- }
- //數據接受正常
- recvLen = recvLen+ret;
- if(recvLen<REVLEN)
- {
- continue;
- }
- else
- {
- //數據接受完畢
- printf("buf = %s\n", recvBuf);
- //close(client[i].fd);
- //client[i].fd = -1;
- recvLen = 0;
- break;
- }
- }
- }
- }
- }
- }
- return 0;
- }
6. epoll函數
2. 常用模型的缺點
如果不擺出來其他模型的缺點,怎麼能對比出 Epoll 的優點呢。
2.1 PPC/TPC 模型
這兩種模型思想類似,就是讓每一個到來的連接一邊自己做事去,別再來煩我 。只是 PPC 是爲它開了一個進程,而 TPC 開了一個線程。可是別煩我是有代價的,它要時間和空間啊,連接多了之後,那麼多的進程 / 線程切換,這開銷就上來了;因此這類模型能接受的最大連接數都不會高,一般在幾百個左右。
2.2 select 模型
1. 最大併發數限制,因爲一個進程所打開的 FD (文件描述符)是有限制的,由 FD_SETSIZE 設置,默認值是 1024/2048 ,因此 Select 模型的最大併發數就被相應限制了。自己改改這個 FD_SETSIZE ?想法雖好,可是先看看下面吧 …
2. 效率問題, select 每次調用都會線性掃描全部的 FD 集合,這樣效率就會呈現線性下降,把 FD_SETSIZE 改大的後果就是,大家都慢慢來,什麼?都超時了??!!
3. 內核 / 用戶空間 內存拷貝問題,如何讓內核把 FD 消息通知給用戶空間呢?在這個問題上 select 採取了內存拷貝方法。
2.3 poll 模型
基本上效率和 select 是相同的, select 缺點的 2 和 3 它都沒有改掉。
3. Epoll 的提升
把其他模型逐個批判了一下,再來看看 Epoll 的改進之處吧,其實把 select 的缺點反過來那就是 Epoll 的優點了。
3.1. Epoll 沒有最大併發連接的限制,上限是最大可以打開文件的數目,這個數字一般遠大於 2048, 一般來說這個數目和系統內存關係很大 ,具體數目可以 cat /proc/sys/fs/file-max 察看。
3.2. 效率提升, Epoll 最大的優點就在於它只管你“活躍”的連接 ,而跟連接總數無關,因此在實際的網絡環境中, Epoll 的效率就會遠遠高於 select 和 poll 。
3.3. 內存拷貝, Epoll 在這點上使用了“共享內存 ”,這個內存拷貝也省略了。
4. Epoll 爲什麼高效
Epoll 的高效和其數據結構的設計是密不可分的,這個下面就會提到。
首先回憶一下 select 模型,當有 I/O 事件到來時, select 通知應用程序有事件到了快去處理,而應用程序必須輪詢所有的 FD 集合,測試每個 FD 是否有事件發生,並處理事件;代碼像下面這樣:
int res = select(maxfd+1, &readfds, NULL, NULL, 120);
if (res > 0)
{
for (int i = 0; i < MAX_CONNECTION; i++)
{
if (FD_ISSET(allConnection[i], &readfds))
{
handleEvent(allConnection[i]);
}
}
}
// if(res == 0) handle timeout, res < 0 handle error
Epoll 不僅會告訴應用程序有I/0 事件到來,還會告訴應用程序相關的信息,這些信息是應用程序填充的,因此根據這些信息應用程序就能直接定位到事件,而不必遍歷整個FD 集合。
int res = epoll_wait(epfd, events, 20, 120);
for (int i = 0; i < res;i++)
{
handleEvent(events[n]);
}
5. Epoll 關鍵數據結構
前面提到 Epoll 速度快和其數據結構密不可分,其關鍵數據結構就是:
struct epoll_event {
__uint32_t events; // Epoll events
epoll_data_t data; // User data variable
};
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
可見 epoll_data 是一個 union 結構體 , 藉助於它應用程序可以保存很多類型的信息 :fd 、指針等等。有了它,應用程序就可以直接定位目標了。
6. 使用 Epoll
既然 Epoll 相比 select 這麼好,那麼用起來如何呢?會不會很繁瑣啊 … 先看看下面的三個函數吧,就知道 Epoll 的易用了。
int epoll_create(int size);
生成一個 Epoll 專用的文件描述符,其實是申請一個內核空間,用來存放你想關注的 socket fd 上是否發生以及發生了什麼事件。 size 就是你在這個 Epoll fd 上能關注的最大 socket fd 數,大小自定,只要內存足夠。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );
控制某個 Epoll 文件描述符上的事件:註冊、修改、刪除。其中參數 epfd 是 epoll_create() 創建 Epoll 專用的文件描述符。相對於 select 模型中的 FD_SET 和 FD_CLR 宏。
op:EPOLL_CTL_ADD
Register the target file descriptor fd on the epoll instance
EPOLL_CTL_MOD
Change the event event associated with the target file descriptor fd.
EPOLL_CTL_DEL
Remove (deregister) the target file descriptor fd from the epoll instance
int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);
等待 I/O 事件的發生;參數說明:
epfd: 由 epoll_create() 生成的 Epoll 專用的文件描述符;
epoll_event: 用於回傳代處理事件的數組;
maxevents: 每次能處理的事件數;
timeout: 等待 I/O 事件發生的超時值,單位 ms
返回發生事件數。
相對於 select 模型中的 select 函數。
- /* 實現功能:通過epoll, 處理多個socket
- * 監聽一個端口,監聽到有鏈接時,添加到epoll_event
- */
- #include "select.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <poll.h>
- #include <sys/epoll.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr; /* client's address information */
- } CLIENT;
- #define MYPORT 59000
- //最多處理的connect
- #define MAX_EVENTS 500
- //當前的連接數
- int currentClient = 0;
- //數據接受 buf
- #define REVLEN 10
- char recvBuf[REVLEN];
- //EPOLL相關
- //epoll描述符
- int epollfd;
- //事件數組
- struct epoll_event eventList[MAX_EVENTS];
- void AcceptConn(int srvfd);
- void RecvData(int fd);
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- int timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
- //socket
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- //bind
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
- //listen
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
- //1. epoll 初始化
- epollfd = epoll_create(MAX_EVENTS);
- struct epoll_event event;
- event.events = EPOLLIN|EPOLLET;
- event.data.fd = sockListen;
- //2. epoll_ctrl
- if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockListen, &event) < 0)
- {
- printf("epoll add fail : fd = %d\n", sockListen);
- return -1;
- }
- //epoll
- while(1)
- {
- timeout=3000;
- //3. epoll_wait
- int ret = epoll_wait(epollfd, eventList, MAX_EVENTS, timeout);
- if(ret < 0)
- {
- printf("epoll error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
- //直接獲取了事件數量,給出了活動的流,這裏是和poll區別的關鍵
- int n = 0;
- for(n=0; n<ret; n++)
- {
- //錯誤退出
- if ((eventList[n].events & EPOLLERR) ||
- (eventList[n].events & EPOLLHUP) ||
- !(eventList[n].events & EPOLLIN))
- {
- printf ( "epoll error\n");
- close (eventList[n].data.fd);
- return -1;
- }
- if (eventList[n].data.fd == sockListen)
- {
- AcceptConn(sockListen);
- }else{
- RecvData(eventList[n].data.fd);
- //不刪除
- // epoll_ctl(epollfd, EPOLL_CTL_DEL, pEvent->data.fd, pEvent);
- }
- }
- }
- close(epollfd);
- close(sockListen);
- printf("test\n");
- return 0;
- }
- /**************************************************
- 函數名:AcceptConn
- 功能:接受客戶端的鏈接
- 參數:srvfd:監聽SOCKET
- ***************************************************/
- void AcceptConn(int srvfd)
- {
- struct sockaddr_in sin;
- socklen_t len = sizeof(struct sockaddr_in);
- bzero(&sin, len);
- int confd = accept(srvfd, (struct sockaddr*)&sin, &len);
- if (confd < 0)
- {
- printf("bad accept\n");
- return;
- }else
- {
- printf("Accept Connection: %d", confd);
- }
- //setnonblocking(confd);
- //4. epoll_wait
- //將新建立的連接添加到EPOLL的監聽中
- struct epoll_event event;
- event.data.fd = confd;
- event.events = EPOLLIN|EPOLLET;
- epoll_ctl(epollfd, EPOLL_CTL_ADD, confd, &event);
- }
- //讀取數據
- void RecvData(int fd)
- {
- int ret;
- int recvLen = 0;
- memset(recvBuf, 0, REVLEN);
- printf("RecvData function\n");
- if(recvLen != REVLEN)
- {
- while(1)
- {
- //recv數據
- ret = recv(fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- recvLen = 0;
- break;
- }
- //數據接受正常
- recvLen = recvLen+ret;
- if(recvLen<REVLEN)
- {
- continue;
- }
- else
- {
- //數據接受完畢
- printf("buf = %s\n", recvBuf);
- recvLen = 0;
- break;
- }
- }
- }
- printf("content is %s", recvBuf);
- }