Chinaunix首页 | 论坛 | 博客
  • 博客访问: 351923
  • 博文数量: 87
  • 博客积分: 1322
  • 博客等级: 少尉
  • 技术积分: 915
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-25 18:04
文章分类

全部博文(87)

文章存档

2013年(10)

2012年(9)

2011年(68)

分类: LINUX

2011-11-26 10:00:38

一、感谢网友提供的例子

1、def.h

#define MAX_LENGTH 1024 

/*包头的结构体定义*/ 
typedef struct tPachHead
{
char iFileSize; /*为0表示发送的是文件名,1表示发送的是数据,2表示发送完毕*/ 
int lPayloadLength; /*当发送的是数据的时候,表示数据的大小*/ 
}PackHead;

/*协议包的结构体定义*/ 
typedef struct tAppPacket
{
PackHead tAppPackHead; /*包头的结构体*/ 
char byData[MAX_LENGTH]; /*数据段*/ 
}AppPacket;

#define MYPORT 8221 /*自定义端口*/ 
#define BACKLOG 10
2、c_s.c

//server & client
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "def.h"
void server_f(int);
void client_f(int);

/*获取文件名的函数*/ 
char *getfn(char *pathname)
{
int i,j;
for(i=0;pathname[i]!='\0';i++);
for(j=i;pathname[j]!='/';j--);
return(&pathname[j+1]);
}

int main()
{
int sockfd;
char c;
while(1) /*主界面循环*/ 
{
if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1) /*socket的建立*/ 
{
perror("socket");
exit(1);
}
printf("(%d)File system:\n",sockfd);
printf("1.Send\n");
printf("2.Recieve\n");
printf("3.Exit\n");
printf(">");
c=fgetc(stdin);getchar();
if(c=='1') /*选择了client端,负责发送,详见client_f函数*/ 
{
client_f(sockfd);
close(sockfd);
continue;
}
else if(c=='2') /*选择了server端,负责接收,详见server_f函数*/ 
{
server_f(sockfd);
close(sockfd);
continue;
}
else if(c=='3') /*退出*/ 
{
close(sockfd);
break;
}
else /*错误的操作*/ 
{
printf("Wrong instruction!\n");
close(sockfd);
continue;
}
}
printf("Bye-bye!\n");
exit(0);
}

/*server端作用函数,负责接收数据*/ 
void server_f(int sockfd)
{
int fd,sin_size,client_fd,recvbytes;
struct sockaddr_in my_addr,opp_addr;
AppPacket info,*pack;
pack=&info;
my_addr.sin_family=PF_INET;
my_addr.sin_port=htons(MYPORT);
my_addr.sin_addr.s_addr=INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1)
{
perror("bind");
close(sockfd);
return;
}
if(listen(sockfd,BACKLOG)==-1)
{
perror("listen");
close(sockfd);
return;
}
printf("Waiting for connection...\n"); /*打印出等待连接信息,并在下面的accept处等待*/ 
if((client_fd=accept(sockfd,(struct sockaddr *)&opp_addr,&sin_size))==-1)
{
perror("accept");
close(client_fd);
close(sockfd);
return;
}
/*有连接过后先接收一个文件名的信息*/ 
if(recv(client_fd,pack,sizeof(AppPacket),0)==-1)
{
perror("recv");
close(client_fd);
close(sockfd);
return;
}
if(((pack->tAppPackHead).iFileSize)==0x00) /*判断为文件名确认信息*/ 
{
char u;
char pathname[100];
int temp;
char *tempbuf;
/*询问是否接收来自[IP]的大小为[大小]的[文件名]文件*/ 
printf("===From %s===\n",inet_ntoa(opp_addr.sin_addr));
printf("Do you wanna recieve %s ?(y)\n",pack->byData); 
printf("SIZE:%d bytes\n",(pack->tAppPackHead).lPayloadLength);/*新加入文件大小信息*/
u=fgetc(stdin);getchar();
if(u=='y'||u=='Y') /*同意接收*/ 
{
while(1) /*存放地址的循环,带出错重输*/ 
{
printf("Type your path to place the file:\n");
scanf("%s",pathname);getchar();
strcat(pathname,pack->byData);
if((fd=open(pathname,O_WRONLY|O_CREAT|O_EXCL,0777))<0)
{
perror("open");
continue;
}
else
break;
}
if(send(client_fd,&u,1,0)<0) /*发送'y'或者'Y',告诉client端同意接收了*/ 
{
perror("Response");
close(fd);
close(client_fd);
close(sockfd);
return;
}
while(1) /*接收循环,以前出错的地方!记住,recv此函数不一定将send来的东西全部读完*/ 
{
/*先接收发过来的包*/
recvbytes=0;
tempbuf=malloc(sizeof(AppPacket)); /*使用临时缓冲区用来recv循环接收socket来的数据*/
while(recvbytes!= sizeof(AppPacket))/*当接收的数据没有达到预期值时,循环接收*/
{
if((temp=recv(client_fd,tempbuf+recvbytes,sizeof(AppPacket)-recvbytes,0))==-1)
{
perror("recv");
close(client_fd);
close(fd);
close(sockfd);
return;
}
recvbytes+=temp;
//printf("%d\n",recvbytes);

}

memcpy(pack,tempbuf,sizeof(AppPacket));/*把在临时缓冲区的数据拷贝到pack里面形成包*/
free(tempbuf);/*开心的释放:)*/
/*然后在下面进行判断是数据还是已经发完了*/ 
if(((pack->tAppPackHead).iFileSize)==0x01)/*来的是数据*/ 
{
write(fd,pack->byData,(pack->tAppPackHead).lPayloadLength);/*写入文件*/ 
// printf("!\n");
continue;
}
else if(((pack->tAppPackHead).iFileSize)==0x02)/*来的是结束信息*/ 
{
printf("Recieve ok!\n");
close(client_fd);
close(fd);
close(sockfd);
break;
}
/*出错处理!多亏了最开始还是考虑到了出错的情况,才得以发现问题!
因此养成出错处理是好习惯,尽管有些错逻辑上是不会出现的~*/ 
else
{
printf("Error.\n");
close(client_fd);
close(fd);
close(sockfd);
return;
}
}
return;
}
else /*不同意接收文件*/ 
{
if(send(client_fd,&u,1,0)<0)/*发非'y'或'Y'给client端表明不同意接收文件*/ 
{
perror("Response");
close(fd);
close(client_fd);
close(sockfd);
return;
}
printf("Connection denied...\n");
close(fd);
close(client_fd);
close(sockfd);
return;
}
}
else /*判断文件名验证信息失败,不是我们的写的协议,出错*/ 
{
printf("File protocol not match!\n");
close(client_fd);
return;
}
}
/*client端处理函数,负责发送文件*/ 
void client_f(int sockfd)
{
int sendbytes,size,fd;
AppPacket info,*pack;
struct hostent *host;
struct sockaddr_in opp_addr;
char pathname[100];
char dest[48],buf[5];
pack=&info;
/*指明发送文件循环,带出错重输*/ 
while(1)
{
printf("Please tell me which file do you wanna send:\n");
scanf("%s",pathname);getchar();
if((fd=open(pathname,O_RDONLY,0777))<0)
{
perror("open");
continue;
}
else
{
struct stat stat;
strcpy(pack->byData,getfn(pathname));
(pack->tAppPackHead).iFileSize=0x00;
fstat(fd,&stat);
(pack->tAppPackHead).lPayloadLength=stat.st_size;/*把文件大小信息也装进去*/
break;
}
}
/*指明发送IP循环,带出错重输*/ 
while(1)
{
printf("And tell me where do you wanna send:\n");
scanf("%s",dest);getchar();
if((host=gethostbyname(dest))==NULL)
{
perror("gethost");
continue;
}
else
break;
}
opp_addr.sin_family=PF_INET;
opp_addr.sin_port=htons(MYPORT);
opp_addr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(opp_addr.sin_zero),8);
/*开始连接server端,前提是server端已经准备好,在等待连接状态,否则返回*/ 
if(connect(sockfd,(struct sockaddr *)&opp_addr,sizeof(struct sockaddr))==-1)
{
perror("connect");
close(fd);
return;
}
/*先把文件名发过去*/ 
if(send(sockfd,pack,sizeof(AppPacket),0)==-1)
{
perror("send filename");
return;
}
printf("Waiting for response...\n");/*打印等待回应信息,并在下面recy处等待*/ 
/*接收请求反馈信息*/
char u;
if(recv(sockfd,&u,1,0)==-1)
{
perror("check");
return;
}
if(u=='y'||u=='Y')/*'y'或者'Y'表示同意*/
{
printf("Sending request accept...\n");
sleep(1);//此处就是因为会出现发送接收不同步的情况,所以我先睡1秒,稳一下*/

/*发送数据的循环*/ 
while((size=read(fd,pack->byData,MAX_LENGTH))>0)
{
(pack->tAppPackHead).iFileSize=0x01;/*因为是数据,所以填1*/ 
(pack->tAppPackHead).lPayloadLength=size;/*读了多少填多少*/ 
if(send(sockfd,pack,sizeof(AppPacket),0)<0)
{
perror("send");
close(fd);
return;
}
}
/*发送完毕,发送结束信息给server端*/ 
memset(pack->byData,0,MAX_LENGTH);
(pack->tAppPackHead).iFileSize=2;/*结束的标志*/ 
(pack->tAppPackHead).lPayloadLength=-1;/*不需要数据大小,防止出错填-1*/ 
if(send(sockfd,pack,sizeof(AppPacket),0)<0)
{
perror("send");
close(fd);
return;
}
printf("Send ok!\n");
close(fd);
return;
}
else /*发送请求被驳回...T_T,太冷血了*/ 
{
printf("Sending request denied...\n");
close(fd);
return;
}
}

二、大文件上传下载,思考多线程编程,类似迅雷

server是父进程,由父进程监听请求,新建一个子进程来应答客户端请求,并且子进程在文件传输前,根据网速开设多线程,使用多个线程共同完成一个进程的任务。

阅读(1445) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~