伺服器程式設計——I/O複用(select、poll、epoll)
select例子:
伺服器上用select來監聽connfd是否就緒,如果是正常資料的話,則正常處理。如果是異常資料的話,則異常處理。伺服器端程式碼:
/*************************************************************************
> File Name: practice_91.c
> Author:
> Mail:
> Created Time: 2016年02月24日 星期三 15時38分01秒
************************************************************************/
/*
能夠同時接收普通資料和帶外資料
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
if(argc <= 2){
printf("%s ip_address port_number\n", argv[0]);
return -1;
}
const char * ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
//socket
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0){
printf("socket error\n");
return -1;
}
//bind
ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
if(ret != 0){
printf("bind error\n");
return -1;
}
//listen
ret = listen(listenfd, 5);
if(ret != 0){
printf("listen error\n");
return -1;
}
//客戶端地址
struct sockaddr_in client_addr;
socklen_t client_addrlen = sizeof(client_addr);
//accept
int connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addrlen);
if(connfd < 0){
printf("accept error\n");
close(listenfd);
return -1;
}
char buf[1024];
fd_set read_fds;
fd_set exception_fds;
FD_ZERO(&read_fds);
FD_ZERO(&exception_fds);
while(1){
memset(buf, 0, sizeof(buf));
FD_SET(connfd, &read_fds);
FD_SET(connfd, &exception_fds);
ret = select(connfd+1, &read_fds, NULL, &exception_fds, NULL);//會一直阻塞,直到檔案描述符就緒;每次事件發生之後,都要再重新設定檔案描述符
if(ret < 0){
printf("select error\n");
break;
}
if(FD_ISSET(connfd, &read_fds)){//正常可讀事件
ret = recv(connfd, buf, sizeof(buf)-1, 0);
if(ret <= 0){//ret == 0表示對方關閉了連線
break;
}
printf("get %d bytes of normal data: %s\n", ret, buf);
}
else if(FD_ISSET(connfd, &exception_fds)){//對於異常事件
ret = recv(connfd, buf, sizeof(buf)-1, MSG_OOB);
if(ret <= 0){//ret == 0表示對方關閉了連線
break;
}
printf("get %d bytes of oob data: %s\n", ret, buf);
}
}
close(connfd);
close(listenfd);
return 0;
}
客戶端程式碼:
/*************************************************************************
> File Name: 53backlog.c
> Author:
> Mail:
> Created Time: 2016年01月16日 星期六 11時35分15秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>//包含bool型別,C語言是沒有bool型別的,C++才有
#include <unistd.h>
#include <errno.h>
static bool stop = false;
static void handle_term(int sig)
{
stop = true;
}
int main(int argc, char *argv[])
{
signal(SIGTERM, handle_term);
if(argc <= 2){
printf("usage: %s ip_address port_number backlog\n", argv[0]);
return 1;
}
const char * ip = argv[1];
int port = atoi(argv[2]);
int backlog = 5;//atoi(argv[3]);
int sock = socket(AF_INET, SOCK_STREAM, 0);
assert(sock >= 0);
//建立ipv4的地址
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, (void *)&address.sin_addr);
int ret = connect(sock, (struct sockaddr *)&address, sizeof(address));
if(ret < 0)
printf("connect failed.\n");
else{
const char * oob_data = "abc";
const char * normal_data = "123";
printf("send the normal_data: %s\n", normal_data);
send(sock, normal_data, strlen(normal_data), 0);
sleep(1);//傳送延遲1秒,如果沒有延遲的話,太快有時候會導致收不到oob_data
printf("send the oob_data: %s\n", oob_data);
send(sock, oob_data, strlen(oob_data), MSG_OOB);
sleep(1);
printf("send the normal_data: %s\n", normal_data);
send(sock, normal_data, strlen(normal_data), 0);
}
printf("send over...,按任意鍵退出\n");
getchar();
close(sock);
return 0;
}
在終端下輸入:./practice_server_91 192.168.0.127 12345 //啟動了伺服器
在另外一個終端下輸入:./56senddata 192.168.0.127 12345 //啟動了客戶端
伺服器終端輸出為:
get 3 bytes of normal data: 123
get 2 bytes of normal data: ab
get 1 bytes of oob data: c
get 3 bytes of normal data: 123
send the normal_data: 123
send the oob_data: abc
send the normal_data: 123
send over...,按任意鍵退出
POLL例項
伺服器和客戶端用poll機制實現,伺服器實現對客戶端的響應的回顯。伺服器將客戶端的輸入直接回復。
伺服器用poll機制實現對監聽套接字和若干連線套接字進行I/O複用。
客戶端用poll機制實現對連線套接字和標準輸入檔案描述符進行I/O複用。
伺服器原始碼:
/*************************************************************************
> File Name: practice_91.c
> Author:
> Mail:
> Created Time: 2016年02月24日 星期三 15時38分01秒
************************************************************************/
/*
能夠同時接收普通資料和帶外資料
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <poll.h>
#include <errno.h>
#define OPEN_MAX 1024
int do_poll(int listenfd)
{
int connfd, sockfd;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
struct pollfd clientfds[1024];
int maxi;
char buf[1024];
int i, num;
int nready;
//新增監聽檔案描述符
clientfds[0].fd = listenfd;
clientfds[0].events = POLLIN;
//初始化客戶連線檔案描述符
for(i = 1; i < OPEN_MAX; ++i){
clientfds[i].fd = -1;
}
maxi = 0;
for(; ;){
//獲取就緒的檔案描述符的個數
nready = poll(clientfds, maxi+1, -1);
if(nready == -1){
printf("poll error\n");
return -1;
}
//測試監聽檔案描述符是否就緒好
if(clientfds[0].revents & POLLIN){
//接受新的連線
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen);
if(connfd == -1){
if(errno == EINTR)
continue;
else{
printf("accept error\n");
return -1;
}
}
printf("接受新的客戶連線:%s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
//將新的連線新增到陣列中
for(i = 1; i < OPEN_MAX; ++i){
if(clientfds[i].fd < 0){
clientfds[i].fd = connfd;
break;
}
}
if(i == OPEN_MAX){
printf("too many clients\n");
return -1;
}
clientfds[i].events = POLLIN;
//記錄客戶連線套接字的個數
maxi = (i > maxi ? i : maxi);
if(--nready <= 0)
continue;
}
//不是監聽套接字就緒
//處理客戶連線,處理連線套接字
//handle_connectin(clientfds, maxi);
memset(buf, 0, 1024);
for(i = 1; i <= maxi; ++i){
if(clientfds[i].fd < 0)
continue;
//測試連線套接字是否就緒可讀
if(clientfds[i].revents & POLLIN){
//有訊息則讀取到buf中
num = read(clientfds[i].fd, buf, 1024);
if(num == 0){
close(clientfds[i].fd);
clientfds[i].fd = -1;
continue;
}
printf("server read the data is : %s", buf);
write(clientfds[i].fd, buf, num);
}
}
}
}
int main(int argc, char *argv[])
{
if(argc <= 2){
printf("%s ip_address port_number\n", argv[0]);
return -1;
}
const char * ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
//socket
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0){
printf("socket error\n");
return -1;
}
//bind
ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
if(ret != 0){
printf("bind error\n");
return -1;
}
//listen
ret = listen(listenfd, 5);
if(ret != 0){
printf("listen error\n");
return -1;
}
do_poll(listenfd);
close(listenfd);
return 0;
}
客戶端原始碼:
/*************************************************************************
> File Name: poll_client.c
> Author:
> Mail:
> Created Time: 2016年02月26日 星期五 20時25分24秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <poll.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
int handle_connection(int sockfd)
{
char sendbuf[1024], recvbuf[1024];
struct pollfd pfds[2];
int num;
//新增連線套接字
pfds[0].fd = sockfd;
pfds[0].events = POLLIN;
//新增標準輸入檔案描述符
pfds[1].fd = STDIN_FILENO;
pfds[1].events = POLLIN;
for(; ;){
poll(pfds, 2, -1);
//連線檔案描述符準備好
if(pfds[0].revents & POLLIN){
num = read(sockfd, recvbuf, 1024);
if(num == 0){
printf("client: server closed.\n");
close(sockfd);
}
//將收到的內容輸出到標準輸出
write(STDOUT_FILENO, recvbuf, num);
}
//測試標準輸入是否就緒
if(pfds[1].revents & POLLIN){
num = read(STDIN_FILENO, sendbuf, 1024);
if(num == 0){
continue;
}
write(sockfd, sendbuf, num);
}
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc <= 2){
printf("input the: %s ipaddr port", argv[0]);
return -1;
}
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
const char * ip = argv[1];
int port = atoi(argv[2]);
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, ip, &servaddr.sin_addr);
servaddr.sin_port = htons(port);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
//處理連線套接字
handle_connection(sockfd);
return 0;
}
在終端1下輸入:./poll_server 192.168.0.140 12345 //啟動了伺服器
在終端2下輸入:./poll_client 192.168.0.140 12345 //啟動了客戶端1
client1 hello world
client1 hello world
client1 linux
client1 linux
在終端3下輸入:./poll_client 192.168.0.140 12345 //啟動了客戶端2
client2 hello world
client2 hello world
client ^H
client
client 2
client 2
伺服器終端輸出為:
接受新的客戶連線:192.168.0.140:59023
server read the data is : client1 hello world
server read the data is : client1 linux
接受新的客戶連線:192.168.0.140:59279
server read the data is : client2 hello world
server read the data is : client
server read the data is : client 2
EPOLL例項
伺服器原始碼:
/*************************************************************************
> File Name: epoll_server.c
> Author:
> Mail:
> Created Time: 2016年02月27日 星期六 16時17分58秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <stdbool.h>
#include <fcntl.h>
#include <errno.h>
#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 10
//設定檔案描述符為非阻塞
int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
//將檔案描述符fd新增到核心事件表中
void addfd(int epollfd, int fd, bool enable_et)
{
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN;
if(enable_et)
event.events |= EPOLLET;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
//LT模式的工作流程
void lt(struct epoll_event * events, int number, int epollfd, int listenfd)
{
char buf[BUFFER_SIZE];
int i;
for(i = 0; i < number; ++i){
int sockfd = events[i].data.fd;
if(sockfd == listenfd){//如果描述符是監聽套接字
struct sockaddr_in clientaddr;
socklen_t clientaddr_len;
int connfd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);
addfd(epollfd, connfd, false);//對connfd禁用et模式
}
else if(events[i].events & EPOLLIN){//如果不是監聽套接字,則是連線套接字,如果可讀則讀取資料,LT模式
printf("event trigger once\n");
memset(buf, 0, BUFFER_SIZE);
int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
if(ret <= 0){
close(sockfd);
continue;
}
printf("get %d bytes data: %s\n", ret, buf);
}
else{
printf("其它情況....\n");
}
}
}
//ET模式的工作流程
void et(struct epoll_event * events, int number, int epollfd, int listenfd)
{
char buf[BUFFER_SIZE];
int i;
for(i = 0; i < number; ++i){
int sockfd = events[i].data.fd;
if(sockfd == listenfd){//如果描述符是監聽套接字
struct sockaddr_in clientaddr;
socklen_t clientaddr_len;
int connfd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);
addfd(epollfd, connfd, true);//對connfd開啟et模式
}
else if(events[i].events & EPOLLIN){//如果不是監聽套接字,則是連線套接字,如果可讀則讀取資料,ET模式,所以要重複的讀完
printf("event trigger once");
while(1){
memset(buf, 0, BUFFER_SIZE);
int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
if(ret < 0){
if((errno==EAGAIN) || (errno==EWOULDBLOCK)){//此時表示讀取完畢
printf("read later, 此時讀取完畢\n");
break;
}
close(sockfd);
break;
}
else if(ret == 0){
close(sockfd);
}
else{
printf("\nget %d bytes data: %s", ret, buf);
}
}
}
else{
printf("其它情況....\n");
}
}
}
int main(int argc, char *argv[])
{
if(argc <= 3){
printf("input: %s ip_addr port_num et or lt", argv[0]);
return -1;
}
const char * ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, ip, &servaddr.sin_addr);
servaddr.sin_port = htons(port);
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0){
printf("socket error\n");
return -1;
}
ret = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
if(ret < 0){
printf("bind error\n");
close(listenfd);
return -1;
}
ret = listen(listenfd, 5);
if(ret < 0){
printf("listen error\n");
close(listenfd);
return -1;
}
struct epoll_event events[MAX_EVENT_NUMBER];
int epollfd = epoll_create(5);
if(epollfd < 0){
printf("epoll_create error\n");
close(listenfd);
}
addfd(epollfd, listenfd, true);//true表示開啟ET模式
while(1){
int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
if(ret < 0){
printf("epoll_wait error\n");
break;
}
if(strncmp(argv[3], "lt", 2) == 0)
lt(events, ret, epollfd, listenfd);
else if(strncmp(argv[3], "et", 2) == 0)
et(events, ret, epollfd, listenfd);
}
close(listenfd);
return 0;
}
客戶端原始碼:
/*************************************************************************
> File Name: 53backlog.c
> Author:
> Mail:
> Created Time: 2016年01月16日 星期六 11時35分15秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>//包含bool型別,C語言是沒有bool型別的,C++才有
#include <unistd.h>
#include <errno.h>
static bool stop = false;
static void handle_term(int sig)
{
stop = true;
}
int main(int argc, char *argv[])
{
signal(SIGTERM, handle_term);
if(argc <= 2){
printf("usage: %s ip_address port_number backlog\n", argv[0]);
return 1;
}
const char * ip = argv[1];
int port = atoi(argv[2]);
int backlog = 5;//atoi(argv[3]);
int sock = socket(AF_INET, SOCK_STREAM, 0);
assert(sock >= 0);
//建立ipv4的地址
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, (void *)&address.sin_addr);
int ret = connect(sock, (struct sockaddr *)&address, sizeof(address));
if(ret < 0)
printf("connect failed.\n");
else{
char buf[1024];
int num = 0;
while(1){
num = read(STDIN_FILENO, buf, 1024);
if(num <= 0){
break;
}
write(sock, buf, num);
}
}
printf("send over...,按任意鍵退出\n");
getchar();
close(sock);
return 0;
}
以LT模式啟動伺服器:
linux
linuxeverreadwrite
haha
伺服器輸出:
event trigger once
get 6 bytes data: linux
event trigger once
get 9 bytes data: linuxever
event trigger once
get 9 bytes data: readwrite
event trigger once
get 1 bytes data:
event trigger once
get 5 bytes data: haha
可以發現第二次的資料比較多,一次不能讀完,然後觸發了該讀事件3次。
以ET模式啟動伺服器:
客戶端輸入:
linux
linuxeverreadwrite
haha
伺服器輸出:
event trigger once
get 6 bytes data: linux
read later, 此時讀取完畢
event trigger once
get 9 bytes data: linuxever
get 9 bytes data: readwrite
get 1 bytes data:
read later, 此時讀取完畢
event trigger once
get 5 bytes data: haha
read later, 此時讀取完畢
EPOLL使用EPOLLONESHOT事件:
伺服器中對每個連線套接字可讀就緒的時候建立新的工作執行緒去處理資料。如果在該執行緒讀取完畢,處理資料過程中,如果該套接字上又有資料輸入了,如果沒有註冊epolloneshot事件則還會建立新的執行緒去處理資料,那麼就會有多個執行緒同時處理一個連線套接字,這樣會出現錯誤的。所以在連線套接字上註冊了epolloneshot事件,那麼只能有一個執行緒在處理該套接字。當該執行緒處理完資料之後,重新註冊該事件,再次檢測到epollin事件的時候再建立一個執行緒去處理資料。
伺服器原始碼:
/*************************************************************************
> File Name: epoll_server.c
> Author:
> Mail:
> Created Time: 2016年02月27日 星期六 16時17分58秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <stdbool.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 1024
struct fds
{
int epollfd;
int sockfd;
};
//設定檔案描述符為非阻塞
int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
//將檔案描述符fd新增到核心事件表中
void addfd(int epollfd, int fd, bool oneshot)
{
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET;
if(oneshot)
event.events |= EPOLLONESHOT;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
void reset_oneshot(int epollfd, int fd)
{
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
}
//處理連線套接字上的資料
void* worker(void* arg)
{
int sockfd = ((struct fds*)arg)->sockfd;
int epollfd = ((struct fds*)arg)->epollfd;
printf("####start new thread to receive data on fd: %d\n", sockfd);
char buf[BUFFER_SIZE];
memset(buf, 0, BUFFER_SIZE);
int ret;
while(1){
ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
if(ret == 0){
close(sockfd);
printf("對端關閉了連線\n");
break;
}
else if(ret < 0){
if(errno == EAGAIN){
reset_oneshot(epollfd, sockfd);
//printf("read later\n");
break;
}
}
else{
printf("get %d bytes data: %s\n", ret, buf);
sleep(4);//模擬此時是正在處理資料
}
memset(buf, 0, BUFFER_SIZE);
}
printf("####end new thread receiving data on fd: %d\n", sockfd);
}
int main(int argc, char *argv[])
{
int i;
if(argc <= 2){
printf("input: %s ip_addr port_num\n", argv[0]);
return -1;
}
const char * ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, ip, &servaddr.sin_addr);
servaddr.sin_port = htons(port);
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0){
printf("socket error\n");
return -1;
}
ret = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
if(ret < 0){
printf("bind error\n");
close(listenfd);
return -1;
}
ret = listen(listenfd, 5);
if(ret < 0){
printf("listen error\n");
close(listenfd);
return -1;
}
struct epoll_event events[MAX_EVENT_NUMBER];
int epollfd = epoll_create(5);
if(epollfd < 0){
printf("epoll_create error\n");
close(listenfd);
}
addfd(epollfd, listenfd, false);
while(1){
int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
if(ret < 0){
printf("epoll_wait error\n");
break;
}
for(i = 0; i < ret; ++i){
int sockfd = events[i].data.fd;
if(sockfd == listenfd){
struct sockaddr_in client_address;
socklen_t client_addresslen = sizeof(client_address);
int connfd = accept(sockfd, (struct sockaddr*)&client_address, &client_addresslen);
//對連線套接字註冊oneshot事件
addfd(epollfd, connfd, true);
}
else if(events[i].events & EPOLLIN){
pthread_t thread;
struct fds fds_for_new_worker;
fds_for_new_worker.sockfd = sockfd;
fds_for_new_worker.epollfd = epollfd;
//啟動新的程式為連線socket服務
pthread_create(&thread, NULL, worker, (void*)&fds_for_new_worker);
}
else{
printf("發生了其它情況\n");
}
}
}
close(listenfd);
return 0;
}
客戶端原始碼同上一樣
linux
lin
lin
lin
linsadfasdf(輸入之後等待超過4秒)
linuxever //此時會啟動新的工作執行緒
liin
####start new thread to receive data on fd: 5
get 6 bytes data: linux
get 4 bytes data: lin
get 4 bytes data: lin
get 4 bytes data: lin
get 12 bytes data: linsadfasdf
####end new thread receiving data on fd: 5
####start new thread to receive data on fd: 5
get 10 bytes data: linuxever
get 5 bytes data: liin
####end new thread receiving data on fd: 5
參考文章:
http://www.cnblogs.com/Anker/p/3265058.html
http://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html
http://www.cnblogs.com/Anker/archive/2013/08/15/3261006.html
http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html
相關文章
- Epoll程式設計-I/O多路複用程式設計
- I/O Mutiplexing poll 和 epoll
- Epoll多路I/O複用技術
- IO模式 select、poll、epoll模式
- 網路程式設計-I/O複用程式設計
- IO多路複用——深入淺出理解select、poll、epoll的實現
- select、poll、epoll之間的區別
- 聊聊select, poll 和 epoll_waitAI
- 淺談 non-blocking I/O Multiplexing + poll/epoll 的正確使用BloC
- 玩轉 PHP 網路程式設計全套之 I/O 複用PHP程式設計
- 【Linux網路程式設計】I/O 多路複用技術Linux程式設計
- Linux IO模式及 select、poll、epoll詳解Linux模式
- 流?I/O 操作?阻塞?epoll?
- 【面試】I/O 複用面試
- select、poll、epoll之間的區別總結[整理]
- 《UNIX網路程式設計》筆記 - select和poll程式設計筆記
- C IO複用select, epoll 簡單總結
- 網路程式設計學習——Linux epoll多路複用模型程式設計Linux模型
- 系統程式設計 - I/O模型程式設計模型
- 面試官:select、poll、epoll有何區別?我:阿巴阿巴...面試
- python網路程式設計——IO多路複用之epollPython程式設計
- I/O多路複用技術(multiplexing)
- Linux下的5種I/O模型與3組I/O複用Linux模型
- Linux IO模式及 select、poll、epoll詳解(含部分例項原始碼)Linux模式原始碼
- linux網路程式設計之socket(十一):套接字I/O超時設定方法和用select實現超時Linux程式設計
- 理解select、epoll
- Linux Shell程式設計(25)——I/O 重定向Linux程式設計
- 從網路I/O模型到Netty,先深入瞭解下I/O多路複用模型Netty
- 伺服器IO多路複用的select和poll的區別以及監聽套接字select函式的四個宏操作伺服器函式
- 計算機I/O與I/O模型計算機模型
- Java 程式設計要點之 I/O 流詳解Java程式設計
- UNIX網路程式設計學習(16)--使用poll的TCP伺服器程式程式設計TCP伺服器
- 設計模式中巧記I/O設計模式
- Netty權威指南:I/O 多路複用技術Netty
- 一文搞懂I/O多路複用及其技術
- 程式設計競賽中 C/C++ I/O 的使用程式設計C++
- 詳解Go語言I/O多路複用netpoller模型Go模型
- 設計複合應用程式:元件設計元件