IPv[46]简单TCP服务器客户端[200行打造]

来源:百度文库 编辑:神马文学网 时间:2024/04/28 04:16:33
/**********************************************
作者:Minuit
时间:2007年01月30日 星期二 04时36分08秒
文件名:tcp6servcli.c
描述:tcp服务器客户端
**********************************************/
#include
#include
#include
#include
#include
#include
#include
#include
enum {
NETINIT_TCPSERV=1,  /*创建一个tcp已经监听套接口服务器*/
NETINIT_TCPCLI,         /*创建一个tcp已经连接套接口客户端*/
NETINIT_TCPCLIBIND,  /*创建一个tcp已经连接并且绑定本IP地址和端口的客户端*/
NETINIT_UDPSERV,   /*创建一个udp已经绑定套接口服务器*/
NETINIT_UDPCLI,    /*创建一个udp客户端*/
NETINIT_UDPCLICONN,  /*创建一个udp并且已经连接服务器套接口客户端*/
NETINIT_BACKLOG=100
};
/*
netinit 所能干的事情就上面那几种
第一个参数主机名或者ip地址(当建服务器时此参数可为空默认BING一个通配的ipv6地址)
第二个参数服务名在/etc/services或者端口号(不能为空)
第三,四参数就不用介绍了说说有什么用处当建立服务器时他返回相关协议的地址长度和地址结构两个都可能为空
根据须要比如建一个服务器当调用accept(2)的时候如果想返回客户机的信息那就要用到第四个参数地址长度(注:accept后两个参数是可选的)又比如客户端想用sendto发送信息到服务器那就可能须要一个服务器的地址如果你填了第三个参数它就返回一个服器的地址结构这个还是很智能的(^_^)当然像udp服务器只有调用recvfrom或者recvmsg才须要第四个参数,udp客户端只用用sendto或者sendmsg时会用到第三个参数总之只要第三,四个参数不空它就会给你填上你想要的东西如果为空那就是你不想让他返回什么(你也可以过后调用get[sock|peer]name系统调用获取你想要的结构信息)
第四个参数已经说过了
*/
int netinit(const char *host,const char *serv,struct sockaddr *addr,socklen_t *addrlen,int flags)
{
struct addrinfo hist,*res,*save;
int sockfd,on=1,errcode;
bzero(&hist,sizeof(struct addrinfo));
if(serv==NULL)
return -1;
hist.ai_family=AF_UNSPEC;
switch(flags)
{
case NETINIT_TCPSERV:
case NETINIT_UDPSERV:
hist.ai_flags=AI_PASSIVE;   /*如果是服务器的话就设置被动模式*/
break;
case NETINIT_TCPCLI:
case NETINIT_UDPCLI:
case NETINIT_UDPCLICONN:
case NETINIT_TCPCLIBIND:
hist.ai_flags=AI_CANONNAME;  /*如果是客户端那就addrinfo结构组成的链表第一个结构里面的一个成员被填充主机名*/
break;
default:
errno=ENOTSUP;  /*不支持有时间把unix域加上*/
return -1;
}
switch(flags)
{
case NETINIT_TCPCLI:
case NETINIT_TCPSERV:
case NETINIT_TCPCLIBIND:
hist.ai_socktype=SOCK_STREAM;  /*udp还是tcp*/
break;
case NETINIT_UDPSERV:
case NETINIT_UDPCLI:
case NETINIT_UDPCLICONN:
hist.ai_socktype=SOCK_DGRAM;
break;
default:
errno=ENOTSUP;
return -1;
}
if((errcode=getaddrinfo(host,serv,&hist,&res))!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(errcode));
return -1;
}
save=res;  /*保存res待会好毁了它*/
do
{
/*创建套接口不管是服务器还是客户端的共同点必须要做的*/
if((sockfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol))>0)
{
/*要绑定地址的者在这里做*/
if(flags==NETINIT_TCPSERV||flags==NETINIT_TCPCLIBIND||flags==NETINIT_UDPSERV)
{
if(flags!=NETINIT_TCPCLIBIND)
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))!=0)  /*给服务器设置端口重用*/
return -1;
if(bind(sockfd,res->ai_addr,res->ai_addrlen)==0)
break;
}
else
{
/*要建连接的者在这里做*/
if(flags!=NETINIT_UDPCLI)
{
if(connect(sockfd,res->ai_addr,res->ai_addrlen)==0)
break;
}
else
break;
}/*如果成功建立套接口那就先出去不然等到链表里的结构都试完了就出去*/
}
close(sockfd);  /*如果创建不成功的话先关闭再说再试下面一个结构*/
} while((res=res->ai_next)!=NULL);
if(res==NULL)  /*如果失败了返回*/
return -1;
if(addr!=NULL)
memcpy(addr,res->ai_addr,res->ai_addrlen);
if(addrlen!=NULL)
*addrlen=res->ai_addrlen;
freeaddrinfo(save);  /*释放addrinfo链表之前已经保存了地址*/
if(flags!=NETINIT_TCPSERV)  /*如果是tcp服务器的话还有一点事没做其它的返回*/
return sockfd;
else
if(listen(sockfd,NETINIT_BACKLOG)!=0)     /*监听套接口*/
return -1;
return sockfd;
}
void usage(char *arg)
{
fprintf(stderr,\
"Usage:%s [-cs] [] \n",\
arg);
exit(-1);
}
int main(int argc,char **argv)
{
struct sockaddr *addr;
socklen_t  addrlen;
int servfd,clifd,pid,c,mode=1;
opterr=0;
while((c=getopt(argc,argv,"cs"))!=EOF)
{
switch(c)
{
case ‘c‘:
mode=0;
break;
case ‘s‘:
mode=1;
break;
default:
usage(argv[0]);
}
}
if((addr=malloc(sizeof(struct sockaddr_in6)))==NULL)
return -1;
c=argc-optind;
switch(c)
{
case 1:
if(!mode)
usage(argv[0]);
servfd=netinit(NULL,argv[optind],addr,NULL,NETINIT_TCPSERV);
break;
case 2:
servfd=netinit(argv[optind],argv[optind+1],addr,mode?NULL:&addrlen,mode?NETINIT_TCPSERV:NETINIT_TCPCLI);
break;
default:
usage(argv[0]);
}
if(servfd==-1)
usage(argv[0]);
if(mode)
{
while(1)
{
if((clifd=accept(servfd,addr,&addrlen))<=0)
{
fprintf(stderr,"accept:%s\n",strerror(errno));
return -1;
}
if((pid=fork())<0)
{
fprintf(stderr,"fork:%s\n",strerror(errno));
return -1;
}
else if(pid==0)
{
char buf[BUFSIZ];
int n;
while((n=read(clifd,buf,BUFSIZ))>0)
write(clifd,buf,n);
exit(0);
}
close(clifd);
}
}
else
{
int n;
char buf[BUFSIZ];
while(1)
{
if(n=read(STDIN_FILENO,buf,BUFSIZ))
{
if(write(servfd,buf,n)!=n)
break;
}
else
break;
if((n=read(servfd,buf,BUFSIZ))>0)
{
if(write(STDOUT_FILENO,buf,n)!=n)
break;
}
else
break;
}
close(servfd);
}
return 0;
}