歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux 網絡編程---->多路復用:select實例!

Linux 網絡編程---->多路復用:select實例!

日期:2017/3/1 10:26:02   编辑:Linux編程
好吧,我承認找了好久,網上都沒有像樣的完整的實例,然後自己參照書自己寫一個吧!

//!> 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;
}
Copyright © Linux教程網 All Rights Reserved