1. 程式人生 > >嵌入式Linux網路程式設計,I/O多路複用,select()示例,select()客戶端,select()伺服器,單鏈表

嵌入式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/Oepoll()示例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/Opoll()示例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/Oselect()示例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/Oselect

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

LinuxI/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,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,

LinuxI/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