嵌入式Linux網路程式設計,I/O多路複用,select()示例,select()客戶端,select()伺服器,單鏈表
文章目錄
1,IO複用select()示例
1.1 select()—net.h
#ifndef __NET_H__
#define __NET_H__
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#define SERV_IP_ADDR "192.168.31.100"
#define SERV_PORT 5002
#define BACKLOG 5
#define QUIT_STR "quite"
#define SERV_RESP_STR "Server:"
#endif
1.2 select()—client.c
/* ./client serv_ip serv_port */
#include "net.h"
void usage(char *s)
{
printf("Usage: %s <serv_ip> <serv_port>\n",s);
printf("\tserv_ip: server ip address\n" );
printf("\tserv_port: server port(>5000)\n ");
}
int main(int argc, const char *argv[])
{
int fd;
short port;
struct sockaddr_in sin;
if(argc != 3)
{
usage((char *)argv[0]);
exit(1);
}
if((port = atoi(argv[2])) < 5000)
{
usage((char *)argv[0]);
exit(1);
}
/* 1 建立socket fd */
if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket");
exit(-1);
}
/* 2 連線伺服器 */
/* 2.1 填充struct sockaddr_in結構體變數*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);//轉為網路位元組序埠號
if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
/* 2.2 連線伺服器*/
if(connect(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror("connect");
goto _error1;
}
printf("client staring ... OK!\n");
fd_set rset;
int maxfd;
struct timeval tout;
char buf[BUFSIZ];
int ret = -1;
while(1)
{
FD_ZERO(&rset);
FD_SET(0,&rset);
FD_SET(fd,&rset);
maxfd = fd;
tout.tv_sec = 5;
tout.tv_usec = 0;
select(maxfd+1,&rset,NULL,NULL,&tout);
if(FD_ISSET(0,&rset))//標準輸入裡面是不是有輸入
{
/* 讀取鍵盤輸入,傳送到網路套接字fd */
bzero(buf,BUFSIZ);
do
{
ret = read(0,buf,BUFSIZ-1);
}while(ret <0 && EINTR == errno);
if(ret < 0)
{
perror("read");
continue ;
}
if(ret == 0)//沒讀到資料
{
continue;
}
if(write(fd,buf,strlen(buf)) < 0)
{
perror("write() to socket");
continue ;
}
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)//退出在傳送之後
{
printf("client is existing!\n");
break;
}
}
if(FD_ISSET(fd,&rset))//伺服器傳送了資料過來
{
/* 讀取套接字資料,處理 */
bzero(buf,BUFSIZ);
do
{
ret = read(fd,buf,BUFSIZ-1);
}while(ret <0 && EINTR == errno);
if(ret < 0)
{
perror("read from socket");
continue ;
}
if(ret == 0)//從套接字中讀到的資料個數小於0,說明伺服器關閉
{
break ;
}
printf("server said: %s",buf);
if((strlen(buf) > strlen(SERV_RESP_STR)) && strncasecmp(buf+strlen(SERV_RESP_STR),QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("sender client is existing!\n");
break;
}
}
}
_error1:
close(fd);
return 0;
}
1.3 select()—sever.c
#include "net.h"
#include "linklist.h"
#include <sys/ioctl.h>
/* IO多路複用select()處理函式 */
void do_select(int fd);
int main(int argc, const char *argv[])
{
int fd;
struct sockaddr_in sin;//如果是IPV6的程式設計,要使用struct sockddr_in6結構體(詳細情況請參考man 7 ipv6),通常更通用的方法可以通過struct sockaddr_storage來程式設計
/* 1 建立socket fd */
if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket");
exit(-1);
}
/* 優化 1 允許繫結地址快速重用 */
int b_reuse = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
/* 2 繫結 */
/* 2.1 填充struct sockaddr_in 結構體變數*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT);
#if 1
/* 優化 2 讓伺服器可以繫結在任意的IP上*/
sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else
if(inet_pton(AF_INET,SERV_IP_ADDR,(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
/* 2.2 繫結*/
if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)))
{
perror("bind");
goto _error1;
}
/* 3 使用listen()把主動套接字變成被動套接字 */
if(listen(fd,BACKLOG) < 0)
{
perror("listen");
goto _error1;
}
do_select(fd);
_error1:
close(fd);
return 0;
}
void do_select(int fd)
{
linklist fdlist,sin_list;//建立一個列表,用於檔案描述符及客戶端資訊儲存
fdlist = create_linklist();
datatype sin_data;//每個物件包括客戶端的socket fd,ipv4地址,埠號
sin_data.fd = fd;
int maxfd = fd;
//struct timeval tout = {5,0};
insert_end_linklist(fdlist,sin_data);//將lsten()處理後的fd加入列表
//show_linklist(fdlist);
fd_set rset;
int newfd = -1;
int ret = -1;
char buf[BUFSIZ];//BUFSIZ是系統提供的
char resp_buf[BUFSIZ+10];
struct sockaddr_in cin;
socklen_t cin_addr_len = sizeof(cin);
/* 用select()函式實現I/O多路複用*/
while(1)
{
int i;
FD_ZERO(&rset);
if(get_length_linklist(fdlist) >= 1)//將列表中的fd加入讀集合進行處理
{
//puts("11111111111111111111111111111");
for(i=0;i<get_length_linklist(fdlist);i++)
{
sin_list = get_list_pos_linklist(fdlist,i);
sin_data = sin_list->data;
FD_SET(sin_data.fd,&rset);
maxfd = sin_data.fd > maxfd ? sin_data.fd : maxfd;
//printf("第 %d 個(fd:%d)(ip:%s)(port:%d)\n",i,sin_data.fd,sin_data.ipv4_addr,sin_data.port);
}
//show_linklist(fdlist);
}
else
{
continue ;
}
//switch(select(maxfd+1,&rset,NULL,NULL,&tout))
switch(select(maxfd+1,&rset,NULL,NULL,NULL))
{
case 0:
{
printf("time out!\n");
goto _error1;
}
case -1:
{
perror("select");
goto _error1;
}
default:
{
if(FD_ISSET(fd,&rset))//有客戶端傳送了連線請求
{
if((newfd = accept(fd,(struct sockaddr *)&cin,&cin_addr_len)) < 0)
{
perror("connect");
goto _error1;
}
/* 將分配成功的套接字newfd設定成非阻塞模式*/
int b_on = 1;
ioctl(newfd, FIONBIO, &b_on);//將分配成功的套接字newfd設定為非阻塞方式
sin_data.fd = newfd;
if(inet_ntop(AF_INET,&cin.sin_addr.s_addr,sin_data.ipv4_addr,sizeof(sin_data.ipv4_addr)) < 0)
{
perror("inet_ntop");
goto _error2;
}
sin_data.port = ntohs(cin.sin_port);
printf("get a new client->(ip:%s)(port:%d)(fd:%d)\n",sin_data.ipv4_addr,sin_data.port,sin_data.fd);
insert_end_linklist(fdlist,sin_data);//將建立客戶端連線的fd加入列表
//show_linklist(fdlist);
}
else//有連線好的客戶端傳送了資料
{
//puts("22222222222222222222");
for(i=0;i<get_length_linklist(fdlist);i++)//將連結串列中的fd都處理一遍
{
sin_list = get_list_pos_linklist(fdlist,i);
sin_data = sin_list->data;
//printf("reading fd is ->(第 %d 個)(fd:%d)(ip:%s)(port:%d)\n",i,sin_data.fd,sin_data.ipv4_addr,sin_data.port);
if(sin_data.fd == fd)//不是建立連線後分配的newfd
continue ;
//puts("########read before");
bzero(buf,BUFSIZ);
do
{
ret = read(sin_data.fd,buf,BUFSIZ-1);
}while(ret < 0 && errno == EINTR);//阻塞讀寫
if(ret < 0)
{
//perror("read");
continue;
}
if(ret == 0)//對方已關閉
{
printf("client is existing!\n");
delete_locate_linklist(fdlist,sin_data);
continue;
}
printf("client ip(:%s) port(:%d) fd(:%d) receive data: %s",sin_data.ipv4_addr,sin_data.port,sin_data.fd,buf);
bzero(resp_buf,BUFSIZ+25);
strncpy(resp_buf,SERV_RESP_STR,strlen(SERV_RESP_STR));
strcat(resp_buf,"ip(");
strcat(resp_buf,sin_data.ipv4_addr);
char s_port[10];
strcat(resp_buf," port(");
sprintf(s_port,"%d",sin_data.port);
strcat(resp_buf,s_port);
strcat(resp_buf," data(");
strcat(resp_buf,buf);
do
{
ret = write(sin_data.fd,resp_buf,strlen(resp_buf));
}while(ret < 0 && EINTR == errno);
//puts("###############################");
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("client (fd:%d)(ip:%s)(potr:%d) is existing!\n",sin_data.fd,sin_data.ipv4_addr,sin_data.port);
delete_locate_linklist(fdlist,sin_data);//將退出的客戶端的fd從列表中刪除
close(sin_data.fd);
//show_linklist(fdlist);
}
}
}
}
}
}
_error2:
close(newfd);
_error1:
close(fd);
clear_linklist(fdlist);
}
1.4 select()—linklist.h
#ifndef __SINGLE_LINKLIST_H__
#define __SINGLE_LINKLIST_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
typedef struct{
int fd;
char ipv4_addr[16];
int port;
}datatype;
typedef struct node{
datatype data;
struct node *next;
}listnode,*linklist;
linklist create_linklist(void);
linklist create_n_linklist(void);
int delete_pos_linklist(linklist L,int pos);
int delete_locate_linklist(linklist L,datatype x);
void clear_linklist(linklist L);
int get_length_linklist(linklist L);
linklist get_list_pos_linklist(linklist L,int pos);
linklist get_list_locate_linklist(linklist L,datatype x);
int insert_head_linklist(linklist L,datatype x);
int insert_n_head_linklist(linklist L);
int insert_end_linklist(linklist L,datatype x);
int insert_n_end_linklist(linklist L);
int insert_pos_linklist(linklist L,datatype x,int pos);
int insert_order_linklist(linklist L,datatype x);
void reverse_linklist(linklist);
void sort_linklist(linklist L);
void show_linklist(linklist L);
#endif
1.5 select()—linklist.c
#include "linklist.h"
linklist create_linklist(void)
{
linklist L;
if((L=(linklist)malloc(sizeof(listnode))
相關推薦
嵌入式Linux網路程式設計,I/O多路複用,epoll()示例,epoll()客戶端,epoll()伺服器,單鏈表
文章目錄
1,I/O多路複用 epoll()示例
1.1,epoll()---net.h
1.2,epoll()---client.c
1.3,epoll()---sever.c
1.4,epoll()---linklist.h
嵌入式Linux網路程式設計,I/O多路複用,poll()示例,poll()客戶端,poll()伺服器,單鏈表
文章目錄
1,IO複用poll()示例
1.1,poll()---net.h
1.2,poll()---client.c
1.3,poll()---sever.c
1.4,poll()---linklist.h
1.5,p
嵌入式Linux網路程式設計,I/O多路複用,select()示例,select()客戶端,select()伺服器,單鏈表
文章目錄
1,IO複用select()示例
1.1 select()---net.h
1.2 select()---client.c
1.3 select()---sever.c
1.4 select()---linklist.h
嵌入式Linux網路程式設計,I/O多路複用,阻塞I/O模式,非阻塞I/O模式fcntl()/ioctl(),多路複用I/O select()/pselect()/poll(),訊號驅動I/O
文章目錄
1,I/O模型
2,阻塞I/O 模式
2.1,讀阻塞(以read函式為例)
2.2,寫阻塞
3,非阻塞模式I/O
3.1,非阻塞模式的實現(fcntl()函式、ioctl() 函式)
Linux網路程式設計---I/O多路複用之select
1.I/O多路複用(IO multiplexing)
我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。
Linux網路程式設計---I/O多路複用之epoll
/*
TCP伺服器
用法:./server port
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string
UNIX網路程式設計-I/O多路複用
目錄
Unix下可用的5種I/O模型
阻塞式I/O模型
非阻塞式I/O模型
I/O複用模型
訊號驅動式I/O模型
非同步I/O模型
各種I/O模型的比較
參考
Unix下可用的5種I/O模型
阻塞式I/O
非阻塞式I/O
Socket網路程式設計_之I/O多路複用
1. IO多路複用:
每一次網路通訊都是一個Socket的I/O流,對於伺服器而言,有兩種方法
1.傳統的多程序併發模型(每進來一個新的I/O流會分配一個新的程序管理。)
2.方法二就是I/O的多路複用
網路程式設計(4)select函式實現I/O多路複用伺服器
我按理解整了個基於select模式的單程序多路複用併發伺服器,並寫了個簡單的測試程式測了下,雖然離實用還差得遠,但用來練習select夠用了。
至於如何實現的細節,程式碼註釋算比較清楚,就不多弄了。
一。伺服器部份
單程序併發伺服器程式碼:
/*********
Java網路程式設計與NIO詳解2:JAVA NIO 一步步構建I/O多路複用的請求模型
微信公眾號【黃小斜】作者是螞蟻金服 JAVA 工程師,專注於 JAVA 後端技術棧:SpringBoot、SSM全家桶、MySQL、分散式、中介軟體、微服務,同時也懂點投資理財,堅持學習和寫作,相信終身學習的力量!關注公眾號後回覆”架構師“即可領取 Java基礎、進階、專案和架構師等免費學習資料,更有資料
從網路I/O模型到Netty,先深入瞭解下I/O多路複用
微信搜尋【阿丸筆記】,關注Java/MySQL/中介軟體各系列原創實戰筆記,乾貨滿滿。
本文是Netty系列第3篇
上一篇文章我們瞭解了Unix標準的5種網路I/O模型,知道了它們的核心區別與各自的優缺點。尤其是I/O多路複用模型,在高併發場景下,有著非常好的優勢。而Netty也採用了I
【Linux】I/O多路複用
五種IO模型
阻塞IO(等待魚上鉤)
在核心將資料準備好之前,系統呼叫會一直等待,所有的套接字,預設是阻塞模式。
等待,拷貝資料到buf中,(等待的時間長)
非阻塞IO(定期檢視是否有魚上鉤)
如果核心還未將資料
I/O多路複用伺服器程式設計
一、實驗目的
理解I/O多路複用技術的原理。
學會編寫基本的單執行緒併發伺服器程式和客戶程式。
二、實驗平臺
ubuntu-8.04作業系統
三、實驗內容
採用I/O多路複用技術實現單執行緒併發伺服器,完成使用一個執行緒處理併發客戶請求的功能。
四、實驗原理
除了可以採用多
淺談網路I/O多路複用模型 select & poll & epoll
我們首先需要知道select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,
Linux 下I/O多路複用總結
select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件
Linux I/O多路複用技術-epoll
Linux I/O多路複用技術在比較多的TCP網路伺服器中有使用,即比較多的用到select函式。Linux 2.6核心中有提高網路I/O效能的新方法,即epoll 。1、為什麼select落後
首先,在Linux核心中,select所用到的FD_SET是有限的
java併發程式設計之IO基礎入門之I/O多路複用技術
在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用多執行緒或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。與傳統的多執行緒/多程序模型比,
從I/O多路複用到Netty,還要跨過Java NIO包
本文是Netty系列第4篇
上一篇文章我們深入瞭解了I/O多路複用的三種實現形式,select/poll/epoll。
那Netty是使用哪種實現的I/O多路複用呢?這個問題,得從Java NIO包說起。
Netty實際上也是一個封裝好的框架,它的網路I/O本質上還是使用了Java的NIO包(New IO
I/O 多路複用
I/O型別: 接下來我們將介紹幾種常見的I/O模型及其區別 阻塞I/O:blocking I/O(如果沒有資訊,則阻塞)  
I/O多路複用技術(multiplexing)
作者:知乎使用者
連結:https://www.zhihu.com/question/28594409/answer/52835876
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
下面舉一個例子,模擬一個tcp伺服器處理30個客戶soc