一、案例简介
二、程序源码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/time.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#define MAXLINE 1024
int max(int f1,int f2);
void str_cli(FILE *fp,int sockfd);
char *gf_time(void);
int main(int argc,char *argv[])
{
if(argc!=3){
perror("please enter [IP] [PORT]");
exit(EXIT_FAILURE);
}
int sockFd=socket(AF_INET,SOCK_STREAM,0);
if(sockFd<0){
perror("socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in serverAddr;
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(atoi(argv[2]));
if((inet_aton(argv[1],(struct in_addr*)&serverAddr.sin_addr))==0){
perror("inet_aton");
exit(EXIT_FAILURE);
}
if(connect(sockFd,(struct sockaddr*)&serverAddr,sizeof(serverAddr))<0){
printf("Connect failed,reasons:%s\n",strerror(errno));
close(sockFd);
exit(EXIT_FAILURE);
}
printf("Connect success\n");
str_cli(stdin,sockFd);
exit(0);
}
void str_cli(FILE *fp,int sockfd)
{
int maxfdp1,val,stdineof,retval;
ssize_t n,nwritten;
fd_set rset,wset;
char to[MAXLINE],fr[MAXLINE]; //to存放标准输入,fr存放标准输出
char *toiptr,*tooptr,*friptr,*froptr;
val=fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,val | O_NONBLOCK);//把sockfd设为非阻塞
val=fcntl(STDIN_FILENO,F_GETFL,0);
fcntl(STDIN_FILENO,F_SETFL,val | O_NONBLOCK);//把标准输入设为非阻塞
val=fcntl(STDOUT_FILENO,F_GETFL,0);
fcntl(STDOUT_FILENO,F_SETFL,val | O_NONBLOCK);//把标准输出设为非阻塞
toiptr=tooptr=to;
friptr=froptr=fr;
stdineof=0;
maxfdp1=max(max(STDIN_FILENO,STDOUT_FILENO),sockfd)+1;
for(;;){
FD_ZERO(&rset);
FD_ZERO(&wset);
if(stdineof==0 && toiptr<&to[MAXLINE])//如果标准输入还可以存放数据
FD_SET(STDIN_FILENO,&rset);
if(friptr<&fr[MAXLINE])
FD_SET(sockfd,&rset);
if(tooptr!=toiptr)
FD_SET(sockfd,&wset);
if(froptr!=friptr)
FD_SET(STDOUT_FILENO,&wset);
switch(retval=select(maxfdp1,&rset,&wset,NULL,NULL))
{
case -1:
perror("select");
continue;
case 0:
printf("timeout\n");
continue;
default:
if(FD_ISSET(STDIN_FILENO,&rset))//从标准输入读取数据
{
if((n=read(STDIN_FILENO,toiptr,&to[MAXLINE]-toiptr))<0){
if(errno!=EWOULDBLOCK)
perror("read error on stdin");
}else if(n==0){
fprintf(stderr,"%s:EOF on stdin\n",gf_time());
stdineof=-1;
if(tooptr==toiptr)//关闭写端
shutdown(sockfd,SHUT_WR);
}else{
fprintf(stderr,"%s:read %d bytes from stdin\n",gf_time(),n);
toiptr+=n;
FD_SET(sockfd,&wset);
}
}
if(FD_ISSET(sockfd,&rset))
{
if((n=read(sockfd,friptr,&fr[MAXLINE]-friptr))<0){
if(errno!=EWOULDBLOCK)
perror("read error on socket");
}else if(n==0){
fprintf(stderr,"%s:EOF on socket\n",gf_time());
if(stdineof)
return;
else
perror("str_cli:server terinated prematurely");
}else{
fprintf(stderr,"%s:read %d bytes from socket\n",gf_time(),n);
friptr+=n;
FD_SET(STDOUT_FILENO,&wset);
}
}
if(FD_ISSET(STDOUT_FILENO,&wset)&&((n=friptr-froptr)>0))
{
if((nwritten=write(STDOUT_FILENO,froptr,n))<0){
if(errno!=EWOULDBLOCK)
perror("write error to stdout");
}else{
fprintf(stderr,"%s:wrote %d bytes to stdout\n",gf_time(),nwritten);
froptr+=nwritten;
if(froptr==friptr)
froptr=friptr=fr;
}
}
if(FD_ISSET(sockfd,&wset)&&((n=toiptr-tooptr)>0))
{
if((nwritten=write(sockfd,tooptr,n))<0){
if(errno!=EWOULDBLOCK)
perror("write error to socket");
}else{
fprintf(stderr,"%s:wrote %d bytes to socket\n",gf_time(),nwritten);
froptr+=nwritten;
if(tooptr==toiptr)
toiptr=tooptr=to;
if(stdineof)
shutdozwn(sockfd,SHUT_WR);
}
}
break;
}
}
}
int max(int f1,int f2)
{
if(f1>f2)
return f1;
else if(f1<f2)
return f2;
else
return f1;
}
char *gf_time(void)
{
struct timeval tv;
static char str[30];
char *ptr;
if(gettimeofday(&tv,NULL)<0)
perror("gettimeofday");
ptr=ctime(&tv.tv_sec);
strcpy(str,&ptr[11]);
snprintf(str+8,sizeof(str)-8,
".%06ld",tv.tv_usec);
return (str);
}