1. server服务器端:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int array_fds[1024];
static void Usage(const char *proc)
{
printf("Usage: %s [local_ip] [local_port]\n",proc);
}
int startup(char *_ip, int _port)//创建套接字 并进行捆绑 监听
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("sock");
exit(2);
}
int flag = 1;
setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = inet_addr(_ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(3);
}
if(listen(sock,10)<0)
{
perror("listen");
exit(4);
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
return 0;
}
int listenSock = startup(argv[1],atoi(argv[2]));
int maxfd = 0;
fd_set rfds;//此类型中每一个bit位对应一个文件描述符
int array_size = sizeof(array_fds)/sizeof(array_fds[0]);
array_fds[0] = listenSock;
int i = 1;
for(;i < array_size;i++)
{
array_fds[i] = -1;
}
while(1){
struct timeval _timeout = {0,0};
FD_ZERO(&rfds);//将rfds中比特位清空
maxfd = -1;
for(i = 0;i<array_size;i++){//从第三方数组中取出数据,设置rfds中对应比特位
if(array_fds[i] > 0){
FD_SET(array_fds[i],&rfds);
if(array_fds[i] > maxfd){
maxfd = array_fds[i];//maxfd最大文件描述符
}
}
}
switch(select(maxfd+1,&rfds,NULL,NULL,NULL/*&_timeout*/)){
case 0:
printf("timeout...\n");
break;
case -1:
perror("select");
break;
default:
{
int j = 0;
for(;j < array_size;j++){
if(array_fds[j]<0){
continue;
}
if(j == 0&&FD_ISSET(array_fds[j],&rfds)){
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_fd = accept(array_fds[j],\
(struct sockaddr*)&client,&len);
if(new_fd < 0){
perror("accept");
continue;
}
else{
printf("get a new client: (%s:%d)\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port));
int k = 1;
for(;k < array_size;k++){
if(array_fds[k] < 0){
array_fds[k] = new_fd;
break;
}
}
if(k == array_size){
close(new_fd);
}
}
}
else if(j != 0&&\
FD_ISSET(array_fds[j],&rfds))
{
char buf[10240];
ssize_t s = read(array_fds[j],buf,sizeof(buf)-1);
if(s>0)
{
buf[s] = 0;
printf("client say: %s\n",buf);
}
else if(s == 0)
{
printf("client quit!\n");
close(array_fds[j]);
array_fds[j] = -1;
}
else
{
perror("read");
close(array_fds[j]);
array_fds[j] = -1;
}
}
else
{
}
}
}
break;
}
}
return 0;
}
2. client客户端:
#include<stdio.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/stat.h>
#include<unistd.h>
static void Usage(char * proc)
{
printf("Usage : %s [ip] [port]\n");
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
return 1;
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in peer;
peer.sin_family = AF_INET;
peer.sin_port = htons(atoi(argv[2]));
peer.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sock, (struct sockaddr*)&peer, sizeof(peer)) < 0)
{
perror("connect");
return 2;
}
char buf[10240];
//int sfd = dup(STDOUT_FILENO);
while(1)
{
printf("Please Enter : ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf)-1);
int sfd = dup(STDOUT_FILENO);
if(s > 0)
{
buf[s-1] = 0;
//write(sock, buf, strlen(buf));
//输出重定向
//close(1);
// int new_fd = dup(sock);
int new_fd = dup2(sock, 1);
if(new_fd == -1)
{
perror("dup()");
return -1;
}
printf("%s",buf);
fflush(stdout);
//恢复stdout
dup2(sfd, STDOUT_FILENO);
ssize_t _s = read(sock, buf, sizeof(buf)-1);
if(_s > 0)
{
buf[_s] = 0;
printf("sever # %s \n", buf);
}
}
}
close(sock);
return 0;
}
3.select服务器优缺点:
优点:
(1)select()的可移植性更好,在某些Unix系统上不支持poll() ;
(2)select() 对于超时值提供了更好的精度:微秒,而poll是毫秒;
(3)select服务器不需要建立多个线程、进程就可以实现一对多的通信;
(4)select服务器可以同时等待多个文件描述符,效率比起多进程多线程来说要高很多。
缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 ;
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 ;
(3)select支持的文件描述符数量太小了,默认是1024。