您的位置:首页 > 理论基础 > 计算机网络

linux 网络编程---->多路复用:select实例!

2012-03-20 11:55 411 查看
好吧,我承认找了好久,网上都没有像样的完整的实例,然后自己参照书自己写一个吧!

//!> server端代码

//!>server.c

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <netinet/in.h>

#include <sys/select.h>

#include <sys/types.h>

#include <sys/socket.h>

#define BUF_LEN 1024

#define SERV_PORT 6000

#define FD_SIZE 100

#define MAX_BACK 100

int main( int argc, char ** argv )

{


int listenfd,connfd, sockfd, maxfd, maxi, i;

int nready,client[FD_SIZE]; //!> 接收select返回值、保存客户端套接字

int lens;

ssize_t n; //!> read字节数

fd_set rset,allset; //!> 不要理解成就只能保存一个,其实fd_set有点像封装的数组

char buf[BUF_LEN];

socklen_t clilen;

structsockaddr_in servaddr, chiaddr;



if( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )

{

printf("Create socket Error : %d\n", errno );

exit(EXIT_FAILURE );

}



//!>

//!> 下面是接口信息

bzero(&servaddr, sizeof( servaddr ) );

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr =htonl( INADDR_ANY);

servaddr.sin_port = htons( SERV_PORT );



//!>

//!> 绑定

if( bind(listenfd, ( struct sockaddr * )&servaddr, sizeof(servaddr ) ) == -1 )

{

printf("BindError : %d\n", errno);

exit(EXIT_FAILURE );

}



//!>

//!> 监听

if( listen(listenfd, MAX_BACK ) == -1 )

{

printf("Listen Error : %d\n", errno );

exit(EXIT_FAILURE );

}



//!> 当前最大的感兴趣的套接字fd

maxfd =listenfd; //!> 当前可通知的最大的fd

maxi =-1; //!> 仅仅是为了client数组的好处理



for( i = 0;i < FD_SIZE; i++) //!> 首先置为全-1

{

client[i] =-1; //!> 首先client的等待队列中是没有的,所以全部置为-1

}



FD_ZERO(&allset); //!> 先将其置为0

FD_SET(listenfd, &allset );

//!> 说明当前我对此套接字有兴趣,下次select的时候通知我!



while( 1)

{

rset =allset;//!> 由于allset可能每次一个循环之后都有变化,所以每次都赋值一次

if( (nready= select( maxfd + 1, &rset, NULL, NULL, NULL )) ==-1)

{ //!> if 存在关注

printf("Select Erorr : %d\n", errno );

exit(EXIT_FAILURE );

}



if( nready<= 0) //!> if 所有的感兴趣的没有就接着回去select

{

continue;

}







if(FD_ISSET( listenfd, &rset )) //!> if 是监听接口上的“来电”

{ //!>

//!> printf("server listen ...\n");

clilen =sizeof( chiaddr );



printf("Start doing... \n");



if( (connfd = accept( listenfd, (struct sockaddr*)&chiaddr, &clilen ) ) == -1)

{ //!> accept
返回的还是套接字

printf("Accept Error : %d\n", errno );

continue;

}





for( i = 0;i < FD_SIZE; i++) //!> 注意此处必须是循环,刚开始我认

//!> 为可以直接设置一个end_i来直接处

//!> 理,实质是不可以的!因为每个套接

{ //!> 字的退出时间是不一样的,后面的

if(client[i] < 0) //!> 可能先退出,那么就乱了,所以只

{ //!> 有这样了!

client[i] =connfd; //!> 将client的请求连接保存

break;

}

}



if( i ==FD_SIZE ) //!> The last one

{

printf( "Tomany ... " );

close(connfd ); //!> if 满了那么就不连接你了,关闭吧

continue; //!> 返回

}

//!> listen的作用就是向数组中加入套接字!

FD_SET(connfd, &allset); //!> 说明现在对于这个连接也是感兴趣的!

//!> 所以加入allset的阵容

if( connfd> maxfd) //!> 这个还是为了解决乱七八糟的数组模型

//!> 的处理

{

maxfd =connfd;

}



if( i> maxi) //!> 同上

{

maxi =i;

}

}

//!> 下面就是处理数据函数( 其实说本质的select还是串行 )

for( i = 0;i <= maxi; i++) //!> 对所有的连接请求的处理

{

if( ( sockfd= client[i] ) > 0) //!> 还是为了不规整的数组

{ //!> 也就说client数组不是连续的全正数或者-1,可能是锯齿状的

if(FD_ISSET( sockfd, &rset )) //!> if 当前这个数据套接字有要读的

{

memset( buf,0, sizeof( buf )); //!> 此步重要,不要有时候出错



n = read(sockfd, buf, BUF_LEN);

if( n< 0 )

{

printf("Error!\n");

close(sockfd ); //!> 说明在这个请求端口上出错了!

FD_CLR(sockfd, &allset );

client[i] =-1;

continue;

}

if( n == 0)

{

printf("nodata\n");

close(sockfd ); //!> 说明在这个请求端口上读完了!

FD_CLR(sockfd, &allset );

client[i] =-1;

continue;

}



printf("Server Recv: %s\n", buf);



if( strcmp(buf, "q" ) == 0) //!> 客户端输入“q”退出标志

{

close(sockfd );

FD_CLR(sockfd, &allset );

client[i] =-1;

continue;

}



printf("Server send : %s\n", buf);

write(sockfd, buf, n); //!> 读出来的写进去

}

}

}



}



return0;

}

//!> client端代码

//!>client.c

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <netinet/in.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <sys/select.h>

#define MAXLINE 1024

#define SERV_PORT 6000

//!> 注意输入是由stdin,接受是由server发送过来

//!> 所以在client端也是需要select进行处理的

void send_and_recv( int connfd )

{

FILE * fp =stdin;

int lens;

charsend[MAXLINE];

charrecv[MAXLINE];

fd_setrset;

FD_ZERO(&rset );

int maxfd =( fileno( fp ) > connfd ? fileno( fp ) :connfd + 1);

//!> 输入和输出的最大值

int n;



while( 1)

{

FD_SET(fileno( fp ), &rset );

FD_SET(connfd, &rset); //!> 注意不要把rset看作是简单的一个变量

//!> 注意它其实是可以包含一组套接字的哦,

//!> 相当于是封装的数组!每次都要是新的哦!



if( select(maxfd, &rset, NULL, NULL, NULL ) == -1 )

{

printf("Client Select Error..\n");

exit(EXIT_FAILURE );

}



//!> if 连接口有信息

if(FD_ISSET( connfd, &rset )) //!> if 连接端口有信息

{

printf("client get from server ...\n" );

memset(recv, 0, sizeof( recv ) );

n = read(connfd, recv, MAXLINE );

if( n == 0)

{

printf("Recvok...\n");

break;

}

else if( n== -1 )

{

printf("Recverror...\n");

break;

}

else

{

lens =strlen( recv );

recv[lens] ='\0';

//!> 写到stdout

write(STDOUT_FILENO, recv, MAXLINE );

printf("\n");

}

}



//!> if 有stdin输入

if(FD_ISSET( fileno( fp ), &rset )) //!> if 有输入

{

//!> printf("client stdin ...\n");



memset(send, 0, sizeof( send ) );

if( fgets(send, MAXLINE, fp ) == NULL )

{

printf("End...\n");

exit(EXIT_FAILURE );

}

else

{

//!>if( str )

lens =strlen( send );

send[lens-1]= '\0'; //!> 减一的原因是不要回车字符

//!> 经验值:这一步非常重要的哦!!!!!!!!

if( strcmp(send, "q" ) == 0 )

{

printf("Bye..\n" );

return;

}



printf("Client send : %s\n", send);

write(connfd, send, strlen( send ) );

}

}



}



}

int main( int argc, char ** argv )

{

//!> char * SERV_IP = "10.30.97.188";

char buf[MAXLINE];

int connfd;

structsockaddr_in servaddr;



if( argc !=2 )

{

printf("Input server ip !\n");

exit(EXIT_FAILURE );

}



//!> 建立套接字

if( ( connfd= socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )

{

printf("Socket Error...\n" , errno );

exit(EXIT_FAILURE );

}

//!> 套接字信息

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(SERV_PORT);

inet_pton(AF_INET, argv[1],&servaddr.sin_addr);



//!> 链接server

if( connect(connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0)

{

printf("Connect error..\n");

exit(EXIT_FAILURE);

}



//!>

//!> send and recv

send_and_recv( connfd );



//!>

close(connfd );

printf("Exit\n");



return0;

}

编译+运行:

gcc -o server server.c

gcc -o client client.c

./server

./client10.80.1.251 (注意参数你指定的server的IP哦 )

如果要多个一起运行,给个脚本:

#!/bin/sh

index=10

while [ $index -gt 0 ]

do

./client 10.80.1.251& # 注意在后台哦,所以只能看到在server下的现象,可以自己改进

$index = `expr $index - 1`

done

exit 0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐