#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#define MAX_SIZE (500) /*数据大小*/
/*数据包*/
typedef struct _data
{
char buf[MAX_SIZE]; /*读取的数据*/
int tatol; /*总包数*/
int number; /*包号*/
long filesize; /*总文件大小*/
int size; /*每包大小*/
char filename[100]; /*文件名*/
}DATA;
/*链表节点*/
typedef struct _node
{
DATA mydata;
struct _node *next;
}NODE;
NODE *head=NULL;
NODE *last=NULL;
NODE *p_buf; /*链表存储空间*/
/*插入链表
DATA temp:插入链表的数据
NODE **temphead:链表头
NODE **templast:链表尾
NODE *p1:数据要插入的地址
返回值:无 */
void insert_link(DATA temp,NODE **temphead,NODE **templast,NODE *p1)
{
p1->mydata = temp;
p1->next=NULL;
if(*temphead==NULL)
{
*temphead=p1;
*templast=p1;
}
else
{
(*templast)->next=p1;
(*templast)=p1;
}
}
struct sockaddr_in udpserver;
socklen_t udpserverlen=sizeof(udpserver);
int listenfd;
char *p; /*判断数据包是否抵达标志*/
int sign; /*线程结束标志 1:结束*/
int tatol; /*总包数*/
/*线程执行函数
根据标志找出未接收的数据包
将包号发送回去*/
void *recv_data(void *arg)
{
while(1)
{
usleep(2000000);
int i;
int t;
int a=0;
int tsign[2]; /*数据包包号*/
int sign1=0; /*数据接收完全标志*/
printf("[%s]\n",p);
/*查找为接收的数据包*/
for (t=0;t<tatol ;t++ )
{
if (*(p+t)=='A')
{
sign1=1;
t++;
if(a++<1) /*得到丢失数据包号tsign[0]~tsign[1]*/
{
tsign[0]=t;
tsign[1]=t;
}
else
tsign[1]=t;
/*发送数据包号*/
if(*(p+t)=='S'||t==tatol)
{
a=0;
if (sendto(listenfd,&tsign,sizeof(tsign),0,
(struct sockaddr*)&udpserver,udpserverlen)==-1)
{
perror("sendto");
exit(EXIT_FAILURE);
}
printf("[lose %d,%d]\n",tsign[0],tsign[1]);
}
t--;
continue;
}
}
/*发送接收完整标志*/
if(sign1!=1)
{
tsign[0]=-1;
for (i=0;i<100 ;i++ )
{
if (sendto(listenfd,&tsign,sizeof(tsign),0,
(struct sockaddr*)&udpserver,udpserverlen)==-1)
{
perror("sendto");
exit(EXIT_FAILURE);
}
}
}
/*线程结束判断*/
if(sign==1)
return NULL;
}
return NULL;
}
int main(int argc, char *argv[])
{
/*socket*/
listenfd=socket(PF_INET,SOCK_DGRAM,0);
if(listenfd==-1)
{
perror("socket");
exit(EXIT_FAILURE);
}
/*初始化*/
memset(&udpserver,0,sizeof(udpserver));
udpserver.sin_family=AF_INET;
udpserver.sin_addr.s_addr = htonl(INADDR_ANY);
udpserver.sin_port = htons(5555);
/*bind*/
if (bind(listenfd,(struct sockaddr*)&udpserver,
udpserverlen)==-1)
{
perror("bind");
exit(EXIT_FAILURE);
}
long tempbuf2=0; /*统计文件大小*/
int i=1;
int j=0;
char bufname[100]=""; /*文件名*/
pthread_t recv_from; /*线程*/
NODE *q=NULL;
/*接收数据包,并处理*/
while (1)
{
/*接收数据包*/
DATA tempbuf;
memset(&tempbuf,0,sizeof(tempbuf));
if (recvfrom(listenfd,&tempbuf,sizeof(tempbuf),0,
(struct sockaddr*)&udpserver,&udpserverlen)==-1)
{
perror("recvfrom");
exit(EXIT_FAILURE);
}
tatol=tempbuf.tatol;
/*只执行一次*/
if (j++<1)
{
strcpy(bufname,tempbuf.filename);
/*开数据标志空间,并初始化*/
p = (char *) malloc(tempbuf.tatol*sizeof(char));
if (p==NULL)
{
perror("1malloc");
exit(EXIT_FAILURE);
}
memset(p,'A',tempbuf.tatol*sizeof(char));
/*创建线程*/
pthread_create(&recv_from,NULL,&recv_data,NULL);
/*开数据存储空间*/
p_buf=(NODE*)malloc(tempbuf.tatol*sizeof(NODE));
if(p_buf==NULL)
{
perror("2malloc");
continue;
}
}
/*数据进链表,并标志*/
if (!strcmp(tempbuf.filename,bufname))
{
if (*(p+(tempbuf.number-1))=='A')
{
*(p+(tempbuf.number-1))='S';
q=p_buf+(tempbuf.number-1);
insert_link(tempbuf,&head,&last,q);
}
else
continue;
}
/*判断是否接收到完整数据,写入文件*/
tempbuf2+=tempbuf.size;
if (tempbuf.filesize==tempbuf2)
{
/*恢复数据,标志*/
tempbuf2=0;
i=1;
j=0;
free(p);
sign=1;
pthread_join(recv_from,NULL);
sign=0;
/*写入文件*/
char buf3[100]="";
sprintf(buf3,"./text/%s",tempbuf.filename);
int fd = open(buf3,O_RDWR|O_CREAT,0644);
if (fd==-1)
{
perror("open");
exit(EXIT_FAILURE);
}
for(i=0,q=p_buf;i<tempbuf.tatol;i++)
{
q=p_buf+i;
if (write(fd,q->mydata.buf,q->mydata.size)==-1)
{
perror("write");
exit(EXIT_FAILURE);
}
}
close(fd);
free(p_buf);
head=NULL;
last=NULL;
printf("Good!\n");
}
}
exit(EXIT_SUCCESS);
}