1.将select的TCP服务器重新搭建
#include <quick.h>
#define PORT 2000
#define IP "192.168.122.76"
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = -1;
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd < 0)
{
perror("socket");
return -1;
}
printf("socket success\n");
//准备bind时使用的结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//设置重用本地地址
int f=1;
setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&f,sizeof(f));
//绑定地址信息
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror("bind");
return -1;
}
printf("bind success\n");
//设置为被动监听状态
if(listen(sfd,10) < 0)
{
perror("listen");
return -1;
}
printf("listenning\n");
//为select做准备
int maxfd = sfd;
fd_set readfd;
fd_set tmpfd;
FD_ZERO(&readfd);
FD_ZERO(&tmpfd);
FD_SET(0,&readfd);
FD_SET(sfd,&readfd);
printf("if you wants send to client\n");
printf("the format is : cfd message\n");
int se_res = -1;
ssize_t res = 0;
char buf[128]="";
int in_cfd = 0;
struct sockaddr_in cin;
struct sockaddr_in allcin[1024];
socklen_t addrlen = sizeof(cin);
while(1)
{
tmpfd = readfd ;
//使用select判断阻塞
se_res = select(maxfd+1,&tmpfd,NULL,NULL,NULL);
if(0 == se_res)
{
printf("time out \n");
break;
}
if(se_res < 0)
{
perror("select");
return -1;
}
printf("select success\n");
for(int i = 0;i <= maxfd;i++)
{
//判断解除阻塞文件描述符号
if(FD_ISSET(i,&tmpfd)==0)
continue;
//判断是否为0号文件描述符
if(0 == i)
{
printf("i == 0\n");
//从终端中读取数据
bzero(buf,sizeof(buf));
res = scanf("%d %s",&in_cfd,buf);
while(getchar() != 10);
//判断数据是否正确
if(res != 2)
{
printf("format error\n");
continue;
}
if(in_cfd < 3 || !FD_ISSET(in_cfd,&readfd))
{
printf("format error\n");
continue;
}
printf("input : %s\n",buf);
//把读取的数据发送到客户端中
if(send(in_cfd,buf,strlen(buf),0) < 0)
{
perror("send");
return -1;
}
printf("send success\n");
continue;
}
//判断是否为sfd文件描述符
else if(sfd == i)
{
printf("i == %d\n",sfd);
//创建客户端文件描述符
int cfd;
cfd = accept(sfd,(struct sockaddr *)&cin,&addrlen);
if(cfd < 0)
{
perror("accept");
return -1;
}
printf("accept success\n");
//在select中添加新文件描述符
allcin[cfd] = cin;
FD_SET(cfd,&readfd);
maxfd = maxfd>cfd?maxfd:cfd;
printf("[%s : %d : %d]\n",inet_ntoa(allcin[cfd].sin_addr),\
ntohs(allcin[cfd].sin_port),cfd);
continue;
}
//判断是否为客户端的文件描述符
else
{
printf("i == %d\n",i);
//接收客户端数据
bzero(buf,sizeof(buf));
res = recv(i,buf,sizeof(buf),0);
if(res < 0)
{
perror("recv");
return -1;
}
//客户端退出,删除客户端数据
if(res == 0)
{
printf("client exited\n");
FD_CLR(i,&readfd);
close(i);
for(;maxfd >= 0;maxfd--)
{
if(maxfd != i)
break;
}
continue;
}
//输出接收的信息在终端上
printf("recv success\n");
printf("[%s : %d : %d]%s\n",inet_ntoa(allcin[i].sin_addr),\
ntohs(allcin[i].sin_port),i,buf);
}
}
}
//关闭套接字
close(sfd);
return 0;
}
2.搭建select的TCP客户端
#include <quick.h>
#define PORT 2000
#define IP "192.168.122.76"
int main(int argc, const char *argv[])
{
//创建流式套接字
int cfd = -1;
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd < 0)
{
perror("socket");
return -1;
}
printf("socket success\n");
//准备传输时使用的结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//连接客户端
if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror("connect");
return -1;
}
printf("connect success\n");
//为select做准备
fd_set readfd;
fd_set tmpfd;
FD_ZERO(&readfd);
FD_ZERO(&tmpfd);
FD_SET(0,&readfd);
FD_SET(cfd,&readfd);
int se_res = -1;
ssize_t res = 0;
char buf[128]="";
socklen_t addrlen = sizeof(sin);
while(1)
{
tmpfd = readfd ;
//使用select判断阻塞
se_res = select(cfd+1,&tmpfd,NULL,NULL,NULL);
if(0 == se_res)
{
printf("time out \n");
break;
}
if(se_res < 0)
{
perror("select");
return -1;
}
printf("select success\n");
for(int i = 0;i <= cfd;i++)
{
//判断解除阻塞文件描述符号
if(FD_ISSET(i,&tmpfd)==0)
continue;
//判断是否为0号文件描述符
if(0 == i)
{
printf("i == 0\n");
//从终端中读取数据
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
//把读取的数据发送到服务器中
if(send(cfd,buf,strlen(buf),0) < 0)
{
perror("send");
return -1;
}
printf("send success\n");
continue;
}
//判断是否为cfd文件描述符
else if(cfd == i)
{
printf("i == %d\n",i);
//接收客户端数据
bzero(buf,sizeof(buf));
res = recv(cfd,buf,sizeof(buf),0);
if(res < 0)
{
perror("recv");
return -1;
}
//输出接收的信息在终端上
printf("recv success\n");
printf("[%s : %d : %d]%s\n",inet_ntoa(sin.sin_addr),\
ntohs(sin.sin_port),cfd,buf);
continue;
}
}
}
//关闭套接字
close(cfd);
return 0;
}
3.搭建poll客户端
#include <quick.h>
#define PORT 2000
#define IP "192.168.122.76"
int main(int argc, const char *argv[])
{
//创建流式套接字
int cfd = -1;
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd < 0)
{
perror("socket");
return -1;
}
printf("socket success\n");
//准备传输时使用的结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//连接客户端
if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror("connect");
return -1;
}
printf("connect success\n");
//为poll做准备
struct pollfd pfd[2];
pfd[0].fd = 0;
pfd[0].events = POLLIN;
pfd[1].fd = cfd;
pfd[1].events = POLLIN;
int p_res = -1;
ssize_t res = 0;
char buf[128]="";
while(1)
{
p_res = poll(pfd,2,-1);
if(p_res < 0)
{
perror("poll");
return -1;
}
if(0 == p_res)
{
printf("time out\n");
break;
}
if((pfd[1].revents&POLLIN)==POLLIN)
{
//接收客户端数据
bzero(buf,sizeof(buf));
res = recv(cfd,buf,sizeof(buf),0);
if(res < 0)
{
perror("recv");
return -1;
}
//输出接收的信息在终端上
printf("recv success\n");
printf("[%s : %d : %d]%s\n",inet_ntoa(sin.sin_addr),\
ntohs(sin.sin_port),cfd,buf);
}
if((pfd[0].revents & POLLIN)==POLLIN)
{
//从终端中读取数据
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
//把读取的数据发送到服务器中
if(send(cfd,buf,strlen(buf),0) < 0)
{
perror("send");
return -1;
}
printf("send success\n");
}
}
//关闭套接字
close(cfd);
return 0;
}
基于UDP的TFTP文件传输
//主函数
#include "head.h"
int main(int argc, const char *argv[])
{
//创建报式套接字
int cli_fd;
cli_fd = socket(AF_INET,SOCK_DGRAM,0);
if(cli_fd<0)
{
ERR_MSG("socket");
return -1;
}
//准备发送对象的信息地址结构体
struct sockaddr_in ser_sin;
ser_sin.sin_family = AF_INET;
ser_sin.sin_port = htons(PORT);
ser_sin.sin_addr.s_addr = inet_addr(IP);
//选择模式
char choose;
while(1)
{
printf("choose mode : (1.DownLoad 2.UpLoad 3.Exit)");
choose = getchar();
while(getchar() != 10);
switch(choose)
{
default :printf("no mode\n");break;
case '1':
//下载
if(DownLoad(cli_fd,ser_sin)<0)
{
printf("DownLoad failed\n");
}
break;
case '2':if(UpLoad(cli_fd,ser_sin)<0)
{
printf("UpLoad failed\n");
}
break;
case '3':goto END;
}
}
END:
//关闭套接字流指针
close(cli_fd);
return 0;
}
//头文件
#ifndef __HEAD_HH__
#define __HEAD_HH__
#include <quick.h>
#define PORT 69
#define IP "192.168.122.27"
int DownLoad(int cli_fd,struct sockaddr_in ser_sin);
int UpLoad(int cli_fd,struct sockaddr_in ser_sin);
#endif
//子函数
#include "head.h"
//下载
int DownLoad(int cli_fd,struct sockaddr_in ser_sin)
{
//从终端中获取下载文件名
printf("please enter a filename : ");
char filename[128]="";
fgets(filename,sizeof(filename),stdin);
filename[strlen(filename)-1]=0;
//创建地址信息结构体,用来存放服务器临时地址信息
struct sockaddr_in tem_sin;
socklen_t addrlen;
//包装读写请求字符串
char readask[128]="";
short *rp1=(short *)readask;
*rp1 = htons(1);
char *rp2=readask+2;
strcpy(rp2,filename);
char *rp3=rp2+strlen(filename)+1;
strcpy(rp3,"octet");
//变量
char dload[516]="";
ssize_t res=0;
size_t len=4+strlen(rp2)+strlen(rp3);
int fd_w = -1;
short c=1;
//发送读写请求
res = sendto(cli_fd,readask,len,0,(struct sockaddr*)&ser_sin,sizeof(ser_sin));
if(res<0)
{
printf("send ask to server failed\n");
return -1;
}
printf("read ask sended\n");
while(1)
{
//接收数据包
bzero(dload,sizeof(dload));
res = recvfrom(cli_fd,dload,516,0,(struct sockaddr *)&tem_sin,&addrlen);
if(res<0)
{
printf("receive failed\n");
return -1;
}
printf("receive finished\n");
if(dload[1]==3)
{
if(*(short *)(dload+2)==htons(c))
{
printf("c = %d\n",c);
c++;
//以写的方式打开文件
if(fd_w == -1)
{
fd_w = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd_w<0)
{
perror("open");
return -1;
}
printf("file has been opened\n");
}
//解析数据,包括临时地址信息
short *wp1 = (short *)dload;
short *wp2 = wp1+1;
char *wp3 = dload+4;
//包装ACK返回信息字符串
char ack[4]="";
short *ap1 = (short *)ack;
*ap1 = htons(4);
short *ap2 = ap1+1;
*ap2 = *wp2;
//返回ACK读取信息完毕信息
if(sendto(cli_fd,ack,4,0,(struct sockaddr*)&tem_sin,sizeof(ser_sin))<0)
{
printf("send ACK to server failed\n");
return -1;
}
printf("ACK sended\n");
//将读取的数据写入文件中
write(fd_w,wp3,res-4);
//判断是否读取完毕
printf("res = %ld\n",res);
if(res < 516)
{
printf("DownLoad finished\n");
break;
}
}
}
else if(dload[1]==5)
{
printf("[%d] : %s\n",dload[3],dload+4);
break;
}
}
close(fd_w);
return 0;
}
//上传
int UpLoad(int cli_fd,struct sockaddr_in ser_sin)
{
//从终端中获取下载文件名
printf("please enter a filename : ");
char filename[128]="";
fgets(filename,sizeof(filename),stdin);
filename[strlen(filename)-1]=0;
//创建地址信息结构体,用来存放服务器临时地址信息
struct sockaddr_in tem_sin;
socklen_t addrlen=sizeof(tem_sin);
//包装读写请求字符串
char readask[128]="";
short *rp1=(short *)readask;
*rp1 = htons(2);
char *rp2=readask+2;
strcpy(rp2,filename);
char *rp3=rp2+strlen(filename)+1;
strcpy(rp3,"octet");
//变量
char ACK[128]="";
ssize_t res=0;
size_t len=4+strlen(rp2)+strlen(rp3);
int fd_r= -1;
char uload[516]="";
short c=0;
//发送读写请求
res = sendto(cli_fd,readask,len,0,(struct sockaddr*)&ser_sin,sizeof(ser_sin));
if(res<0)
{
printf("send ask to server failed\n");
return -1;
}
printf("read ask sended\n");
while(1)
{
//接收数据包
bzero(ACK,sizeof(ACK));
res = recvfrom(cli_fd,ACK,sizeof(ACK),0,(struct sockaddr *)&tem_sin,&addrlen);
if(res<0)
{
printf("receive failed\n");
return -1;
}
printf("receive finished\n");
if(ACK[1]==4)
{
printf("ACK[3]=%d\n",ACK[3]);
if(*(short *)(ACK+2)==htons(c))
{
c++;
//以读的方式打开文件
if(fd_r == -1)
{
fd_r = open(filename,O_RDONLY);
if(fd_r<0)
{
perror("open");
return -1;
}
printf("file has been opened\n");
}
//解析数据,包括临时地址信息
short *ap2 = (short *)(ACK + 2);
//包装发送数据包
bzero(uload,sizeof(uload));
short *up1 = (short *)uload;
*up1 = htons(3);
short *up2 = up1 + 1;
*up2 = htons(c);
//从文件中读取数据
res=read(fd_r,uload+4,sizeof(uload)-4);
if(res<0)
{
perror("read");
return -1;
}
//上传文件内容
if(sendto(cli_fd,uload,res+4,0,(struct sockaddr*)&tem_sin,sizeof(tem_sin))<0)
{
printf("send uload to server failed\n");
return -1;
}
printf("uload sended\n");
//判断是否读取完毕
printf("res = %ld\n",res);
if(res < 512)
{
printf("UpLoad finished\n");
break;
}
}
}
else if(ACK[1]==5)
{
printf("[%d] : %s\n",ACK[3],ACK+4);
break;
}
}
close(fd_r);
return 0;
}