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

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

文章目錄

1,IO複用poll()示例

1.1,poll()—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,poll()—client.c

/* ./client serv_ip serv_port */
#include "net.h"
#include "poll.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 "); } void client_do_poll(int fd); 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"); client_do_poll(fd); _error1: close(fd); return 0; } void client_do_poll(int fd) { char buf[BUFSIZ]; int ret = -1; struct pollfd f[2];//將需要監聽的fd放入陣列中 f[0].fd = fd;//新增連線描述符 f[0].events = POLLIN; f[1].fd = STDIN_FILENO;//新增標準輸入描述符 f[1].events = POLLIN; while(1) { poll(f,2,-1); if(f[1].revents & POLLIN)//標準輸入裡面是不是有輸入 { /* 讀取鍵盤輸入,傳送到網路套接字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(f[0].revents & POLLIN)//伺服器傳送過來了資料 { /* 讀取套接字資料,處理 */ 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; } } } close(fd); }

1.3,poll()—sever.c

#include "net.h"
#include "linklist.h"
#include <sys/ioctl.h>

#define MAX_LEN 10  //poll函式掃描的fd陣列的最大空間

/* IO多路複用poll()處理函式 */
void sever_do_poll(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;
	}
	
	sever_do_poll(fd);

_error1:
	close(fd);
	return 0;
}


void sever_do_poll(int fd)
{
	linklist fdlist,sin_list;//建立一個列表,用於檔案描述符及客戶端資訊儲存
	fdlist = create_linklist();
	datatype sin_data;//每個物件包括客戶端的socket fd,ipv4地址,埠號
	sin_data.pfds.fd = fd;
	sin_data.pfds.events = POLLIN;
	int maxfd = fd;
	//struct timeval tout = {5,0};

	insert_end_linklist(fdlist,sin_data);//將lsten()處理後的fd加入列表
	//show_linklist(fdlist);
	
	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);
	/* 用poll()函式實現I/O多路複用*/
	while(1)
	{
		int i;
		struct pollfd refd[MAX_LEN];
		for(i=0;i<MAX_LEN;i++)
		{
			refd[i].fd = -1;
		}
		if(get_length_linklist(fdlist) >= 1)//將列表中的fd加入讀集合進行處理
		{
			for(i=0;i<get_length_linklist(fdlist);i++)
			{
				sin_list = get_list_pos_linklist(fdlist,i);
				sin_data = sin_list->data;
				refd[i].fd = sin_data.pfds.fd;
				refd[i].events = sin_data.pfds.events;
				maxfd = i;
				//printf("第 %d 個(fd:%d)(ip:%s)(port:%d)\n",i,sin_data.pfds.fd,sin_data.ipv4_addr,sin_data.port);
			}
		}
		else
		{
			continue ;
		}
		switch(poll(refd,maxfd+1,-1))
		{
			case 0:
			{
				printf("time out!\n");
				goto _error1;
			}
			case -1:
			{
				perror("select");
				goto _error1;
			}
			default:
			{
				sin_data.pfds.fd = fd;
				sin_list = get_list_locate_linklist(fdlist,sin_data);
				sin_data = sin_list->data;
				if(refd[0].revents & POLLIN)//有客戶端傳送了連線請求
				{
					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.pfds.fd = newfd;
					sin_data.pfds.events = POLLIN;
					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.pfds.fd);
					
					insert_end_linklist(fdlist,sin_data);//將建立客戶端連線的fd加入列表
					//show_linklist(fdlist);
				}
				else//有連線好的客戶端傳送了資料
				{
					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.pfds.fd,sin_data.ipv4_addr,sin_data.port);
						if(sin_data.pfds.fd == fd)//不是建立連線後分配的newfd
							continue ;
						//puts("########read before");
						bzero(buf,BUFSIZ);
						do
						{
							ret = read(sin_data.pfds.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.pfds.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.pfds.fd,resp_buf,strlen(resp_buf));
						}while(ret < 0 && EINTR == errno);
						if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
						{
							printf("client (fd:%d)(ip:%s)(potr:%d) is existing!\n",sin_data.pfds.fd,sin_data.ipv4_addr,sin_data.port);
							delete_locate_linklist(fdlist,sin_data);//將退出的客戶端的fd從列表中刪除
							close(sin_data.pfds.fd);
							//show_linklist(fdlist);
						}
					}
				}
			
			}
		}
	}

_error2:
	close(newfd);
_error1:
	close(fd);
	clear_linklist(fdlist);//將連結串列記憶體釋放

}

1.4,poll()—linklist.h

#ifndef __SINGLE_LINKLIST_H__
#define __SINGLE_LINKLIST_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/poll.h>

typedef struct{
	struct pollfd pfds;
	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);