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

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

2015-12-07 13:35 731 查看
好吧,我承认找了好久,网上都没有像样的完整的实例,然后自己参照书自己写一个吧!

//!> 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;

struct
sockaddr_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("Bind
Error : %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(
"To many ... " );

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("no
data\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 ); //!>
读出来的写进去

}

}

}



}



return
0;

}

//!> 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;

char
send[MAXLINE];

char
recv[MAXLINE];

fd_set
rset;

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("Recv
ok...\n");

break;

}

else
if( n == -1 )

{

printf("Recv
error...\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;

struct
sockaddr_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");



return
0;

}

编译+运行:

gcc -o server server.c

gcc -o client client.c

./server

./client 10.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

FROM: http://blog.sina.com.cn/s/blog_6dc9e4cf0100ycuw.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐