linklist.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 300
typedef struct Node{
char fname[N];
struct Node *next;
}linkList;
linkList *list_creat();
linkList *node_buy(char *name);
int list_empty(linkList *h);
int list_insert_head(linkList *h,char *name);
int list_delete(linkList *h,char *name);
int list_find(linkList *h,char *name);
int list_delete_head(linkList *h);
int list_destroy(linkList *h);
#endif
linklist.c
#include "linklist.h"
//头节点的创建
linkList *list_creat()
{
linkList *h=(linkList *)malloc(sizeof(linkList));
if(NULL==h){
return NULL;
}
h->next=NULL;
return h;
}
//申请节点
linkList *node_buy(char *name)
{
linkList *p=(linkList *)malloc(sizeof(linkList));
if(NULL==p){
return NULL;
}
strcpy(p->fname,name);
p->next=NULL;
return p;
}
//判空
int list_empty(linkList *h)
{
if(NULL==h){
return -1;
}
return h->next==NULL ? 1 : 0;
}
//头插法
int list_insert_head(linkList *h,char *name)
{
if(NULL==h){
return -1;
}
linkList *l=node_buy(name);
if(NULL==l){
return -2;
}
l->next=h->next;
h->next=l;
return 0;
}
//删除目标
int list_delete(linkList *h,char *name)
{
if(NULL==h){
return -1;
}
if(list_empty(h)){
return -2;
}
linkList *p=h->next;
while(p->next!=NULL){
if(strcmp(p->fname,name)==0)
break;
else
p=p->next;
}
while(h->next!=p){
h=h->next;
}
h->next=p->next;
free(p);
return 0;
}
//查找成员是否存在
int list_find(linkList *h,char *name)
{
if(NULL==h || list_empty(h)){
return -1;
}
while(h->next!=NULL){
h=h->next;
if(strcmp(h->fname,name)==0){
return 0;
}
}
return -1;
}
//头删
int list_delete_head(linkList *h)
{
if(NULL==h){
return -1;
}
if(!list_empty(h)){
linkList *p=h->next;
h->next=p->next;
free(p);
}else{
return -1;
}
return 0;
}
//销毁链表
int list_destroy(linkList *h)
{
while(list_delete_head(h)==0);
return 0;
}
Server:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <semaphore.h>
typedef void (*sighandler_t)(int);
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%s__ __%d__\n",__func__,__LINE__);\
perror(msg);\
}while(0)
int newfd;
sem_t sem0,sem1,sem2;
//定义存储客户端地址信息的结构体
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
//僵尸进程处理函数
void handler(int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
//函数声明
void *callBack_up(void *);
void *callBack_down(void *);
//避免TCP粘包函数
int writen(int fd,char *msg,int size);
int sendMsg(int fd,char *msg,int size);
int readn(int fd,char *msg,int size);
int recvMsg(int fd,char **msg);
int main(int argc, const char *argv[])
{
if(argc<3){
fprintf(stderr,"传参不足 %s ip port\n",argv[0]);
return -1;
}
//创建流式套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0){
ERR_MSG("socket");
return -1;
}
//填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[2]));
sin.sin_addr.s_addr=inet_addr(argv[1]);
//绑定ip和端口
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0){
ERR_MSG("bind");
return -1;
}
//设置为被动监听状态
if(listen(sfd,10)<0){
ERR_MSG("bind");
return -1;
}
//信号处理僵尸进程
if(signal(SIGCHLD,handler)==SIG_ERR){
ERR_MSG("signal");
return -1;
}
//循环等待客户端连接
while(1){
newfd=accept(sfd,(struct sockaddr *)&cin,&addrlen);
if(newfd<0){
ERR_MSG("accept");
return -1;
}
printf("[ %s : %d ]connect\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
//如果有客户端连接就去创建一个子进程与客户端通信
//父进程继续等待其他客户端连接
pid_t pid=fork();
if(pid>0){
close(newfd);
continue;
}else if(0==pid){
close(sfd);
break;
}else{
ERR_MSG("fork");
return -1;
}
}
char *msg;
//初始化信号量
sem_init(&sem0,0,1);
sem_init(&sem1,0,0);
sem_init(&sem2,0,0);
//出来的是子进程
//子进程拷贝父进程的newfd与客户端通信
//子进程创建两个线程分别执行下载与上传操作
pthread_t uptid,downtid;
if(pthread_create(&uptid,NULL,callBack_up,NULL)!=0){
ERR_MSG("pthread_create");
return -1;
}
if(pthread_create(&downtid,NULL,callBack_down,NULL)!=0){
ERR_MSG("pthread_create");
return -1;
}
while(1){
sem_wait(&sem0);
if((recvMsg(newfd,&msg))!=1){
ERR_MSG("recv");
exit(-1);
}
if(msg[0]=='x'){
free(msg);
sem_post(&sem1);
continue;
}else if(msg[0]=='s'){
free(msg);
sem_post(&sem2);
continue;
}else if(msg[0]=='q'){
printf("[ %s : %d ]quit\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
free(msg);
exit(0);
}else{
sem_post(&sem0);
}
}
pthread_join(uptid,NULL);
pthread_join(downtid,NULL);
//关闭套接字
close(sfd);
return 0;
}
//下载处理
void *callBack_up(void *arg)
{
char buf[256];
char *msg;
ssize_t res;
DIR *df=NULL;
FILE *fd=NULL;
while(1){
sem_wait(&sem1);
df=opendir("./");
if(NULL==df){
ERR_MSG("opendir");
exit(-1);
}
struct dirent *sdr;
while(1){
sdr=readdir(df);
if(NULL==sdr){
if(errno!=0){
ERR_MSG("readdir");
exit(-1);
}else{
closedir(df);
buf[0]=']';
sendMsg(newfd,buf,res+1);
break;
}
}
if(sdr->d_name[0]=='.'){
continue;
}
bzero(buf,sizeof(buf));
buf[0]='[';
strcpy(buf+1,sdr->d_name);
sendMsg(newfd,buf,strlen(buf)+1);
}
while(1){
res=recvMsg(newfd,&msg);
if(msg[0]=='['){
fd=fopen(msg+1,"r");
if(NULL==fd){
ERR_MSG("fopen");
exit(-1);
}
free(msg);
}else if(msg[0]==']'){
free(msg);
break;
}
while(1){
buf[0]='[';
if((res=fread(buf+1,1,sizeof(buf)-1,fd))<sizeof(buf)-1){
buf[0]=']';
sendMsg(newfd,buf,res+1);
fclose(fd);
break;
}else{
sendMsg(newfd,buf,res+1);
}
}
}
sem_post(&sem0);
}
pthread_exit(NULL);
}
//上传处理
void *callBack_down(void *arg)
{
char buf[256];
char *msg;
ssize_t res;
FILE *fd=NULL;
while(1){
sem_wait(&sem2);
while(1){
res=recvMsg(newfd,&msg);
if(msg[0]=='['){
fd=fopen(msg+1,"w");
if(NULL==fd){
ERR_MSG("fopen");
exit(-1);
}
free(msg);
}else if(msg[0]==']'){
free(msg);
break;
}
while(1){
res=recvMsg(newfd,&msg);
if(msg[0]==']'){
fwrite(msg+1,1,res-1,fd);
free(msg);
fclose(fd);
break;
}else if(msg[0]=='['){
fwrite(msg+1,1,res-1,fd);
free(msg);
}
}
}
sem_post(&sem0);
}
}
//发送指定大小数据
int writen(int fd,char *msg,int size)
{
char *buf=msg;
int count=size;
while(count>0){
int len=send(fd,buf,count,0);
if(len<0){
ERR_MSG("send");
return -1;
}else if(0==len){
return size-count;
}
buf+=len;
count-=len;
}
return size;
}
//发送数据
int sendMsg(int fd,char *msg,int size)
{
if(fd<0 || msg==NULL || size<=0){
return -1;
}
char *buf=(char *)malloc(size+4);
int len=htonl(size);
memcpy(buf,(char *)&len,4);
memcpy(buf+4,msg,size);
int res=writen(fd,buf,size+4);
if(res<size+4){
free(buf);
fprintf(stderr,"发送失败\n");
return -1;
}
free(buf);
return size;
}
//接受指定大小数据
int readn(int fd,char *msg,int size)
{
char *buf=msg;
int count=size;
while(count>0){
int len=recv(fd,buf,count,0);
if(len<-1){
ERR_MSG("recv");
return -1;
}else if(0==len){
fprintf(stderr,"对方退出\n");
return count-len;
}
buf+=len;
count-=len;
}
return size;
}
//接受数据
int recvMsg(int fd,char **msg)
{
int len;
recv(fd,&len,4,0);
len=ntohl(len);
char *buf=(char *)malloc(len+1);
int res=readn(fd,buf,len);
if(res<len){
fprintf(stderr,"接收失败\n");
free(buf);
return -1;
}
buf[len]='\0';
*msg=buf;
return len;
}
Client:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <dirent.h>
#include "./linklist.h"
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%s__ __%d__\n",__func__,__LINE__);\
perror(msg);\
}while(0)
int cfd;
sem_t sem0,sem1,sem2;
//函数声明
void *callBack_up(void *);
void *callBack_down(void *);
//避免TCP粘包处理函数
int writen(int fd,char *msg,int size);
int sendMsg(int fd,char *msg,int size);
int readn(int fd,char *msg,int size);
int recvMsg(int fd,char **msg);
int main(int argc, const char *argv[])
{
if(argc<3){
fprintf(stderr,"传参不足 %s ip port\n",argv[0]);
return -1;
}
//创建流式套接字
cfd=socket(AF_INET,SOCK_STREAM,0);
if(cfd<0){
ERR_MSG("socket");
return -1;
}
//非绑定
//填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[2]));
sin.sin_addr.s_addr=inet_addr(argv[1]);
//连接服务器
if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin))<0){
ERR_MSG("connect");
return -1;
}
char msg;
//初始化信号量
sem_init(&sem0,0,1);
sem_init(&sem1,0,0);
sem_init(&sem2,0,0);
//创建两个线程分别执行下载与上传操作
pthread_t uptid,downtid;
if(pthread_create(&uptid,NULL,callBack_up,(void *)&msg)!=0){
ERR_MSG("pthread_create");
return -1;
}
if(pthread_create(&downtid,NULL,callBack_down,(void *)&msg)!=0){
ERR_MSG("pthread_create");
return -1;
}
int choose=0;
while(1){
TRY:
sem_wait(&sem0);
printf("\t**********************\n");
printf("\t*****文件传输系统*****\n");
printf("\t*******1>> 下载*******\n");
printf("\t*******2>> 上传*******\n");
printf("\t*******3>> 退出*******\n");
printf("\t**********************\n");
printf("请输入你的选择>>>");
scanf("%d",&choose);
while(getchar()!='\n');
switch(choose){
case 1:
msg='x';
sendMsg(cfd,&msg,1);
sem_post(&sem1);
break;
case 2:
msg='s';
sendMsg(cfd,&msg,1);
sem_post(&sem2);
break;
case 3:
msg='q';
sendMsg(cfd,&msg,1);
printf("正在退出...\n");
close(cfd);
exit(0);
break;
default:
printf("选择有误,请重试!!\n");
goto TRY;
}
}
pthread_join(uptid,NULL);
pthread_join(downtid,NULL);
close(cfd);
return 0;
}
//下载处理
void *callBack_up(void *arg)
{
char buf[256];
char *msg;
ssize_t res;
linkList *file=list_creat();
FILE *fd=NULL;
while(1){
sem_wait(&sem1);
int i=0;
int flag=0;
printf("服务器中文件如下:\n");
while(1){
recvMsg(cfd,&msg);
if(msg[0]==']'){
break;
}else if(msg[0]=='['){
printf("%s\t",msg+1);
list_insert_head(file,msg+1);
free(msg);
i++;
if(i%5==0){
putchar(10);
}
}
}
if(i%5!=0){
putchar(10);
}
while(1){
if(flag==0){
bzero(buf,sizeof(buf));
buf[0]='[';
printf("请输入你要下载的文件名>>>");
fgets(buf+1,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if(list_find(file,buf+1)!=0){
fprintf(stderr,"文件不存在,请重试!!\n");
continue;
}
}else{
buf[0]=']';
}
sendMsg(cfd,buf,strlen(buf)+1);
if(flag==1){
break;
}
printf("正在下载....\n");
fd=fopen(buf+1,"w");
if(NULL==fd){
ERR_MSG("fopen");
exit(-1);
}
while(1){
res=recvMsg(cfd,&msg);
if(msg[0]==']'){
fwrite(msg+1,1,res-1,fd);
free(msg);
fclose(fd);
break;
}else if(msg[0]=='['){
fwrite(msg+1,1,res-1,fd);
free(msg);
}
}
printf("下载完毕\n");
printf("是否继续下载其他文件?(Y|y N|n)>>>");
char ch=getchar();
while(getchar()!='\n');
if(ch=='Y'||ch=='y'){
flag=0;
}else{
flag=1;
}
}
list_destroy(file);
sem_post(&sem0);
}
pthread_exit(NULL);
}
//上传处理
void *callBack_down(void *arg)
{
char buf[256];
char *msg;
ssize_t res;
char ch;
DIR *df;
FILE *fd=NULL;
linkList *file=list_creat();
while(1){
sem_wait(&sem2);
int flag=0;
int i=0;
printf("本地文件如下:\n");
df=opendir("./");
if(NULL==df){
ERR_MSG("opendir");
exit(-1);
}
struct dirent *sdr;
while(1){
sdr=readdir(df);
if(NULL==sdr){
if(errno!=0){
ERR_MSG("readdir");
exit(-1);
}else{
closedir(df);
break;
}
}
if(sdr->d_name[0]=='.'){
continue;
}
printf("%s\t",sdr->d_name);
i++;
if(i%5==0){
putchar(10);
}
list_insert_head(file,sdr->d_name);
}
if(i%5!=0){
putchar(10);
}
while(1){
if(flag==0){
bzero(buf,sizeof(buf));
buf[0]='[';
printf("请输入你要上传的文件名>>>");
fgets(buf+1,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if(list_find(file,buf+1)!=0){
fprintf(stderr,"文件不存在,请重试!!\n");
continue;
}
}else{
buf[0]=']';
}
sendMsg(cfd,buf,strlen(buf)+1);
if(flag==1){
break;
}
printf("正在上传....\n");
fd=fopen(buf+1,"r");
if(NULL==fd){
ERR_MSG("fopen");
exit(-1);
}
while(1){
buf[0]='[';
if((res=fread(buf+1,1,sizeof(buf)-1,fd))<sizeof(buf)-1){
buf[0]=']';
sendMsg(cfd,buf,res+1);
fclose(fd);
break;
}else{
sendMsg(cfd,buf,res+1);
}
}
printf("上传完毕\n");
printf("是否继续上传其他文件?(Y|y N|n)>>>");
ch=getchar();
while(getchar()!='\n');
if(ch=='Y'||ch=='y'){
flag=0;
}else{
flag=1;
}
}
list_destroy(file);
sem_post(&sem0);
}
pthread_exit(NULL);
}
//发送指定大小数据
int writen(int fd,char *msg,int size)
{
char *buf=msg;
int count=size;
while(count>0){
int len=send(fd,buf,count,0);
if(len<0){
ERR_MSG("send");
return -1;
}else if(0==len){
return size-count;
}
buf+=len;
count-=len;
}
return size;
}
//发送数据
int sendMsg(int fd,char *msg,int size)
{
if(fd<0 || msg==NULL || size<=0){
return -1;
}
char *buf=(char *)malloc(size+4);
int len=htonl(size);
memcpy(buf,(char *)&len,4);
memcpy(buf+4,msg,size);
int res=writen(fd,buf,size+4);
if(res<size+4){
free(buf);
fprintf(stderr,"发送失败\n");
return -1;
}
free(buf);
return size;
}
//接受指定大小数据
int readn(int fd,char *msg,int size)
{
char *buf=msg;
int count=size;
while(count>0){
int len=recv(fd,buf,count,0);
if(len<-1){
ERR_MSG("recv");
return -1;
}else if(0==len){
fprintf(stderr,"对方退出\n");
return count-len;
}
buf+=len;
count-=len;
}
return size;
}
//接受数据
int recvMsg(int fd,char **msg)
{
int len;
recv(fd,&len,4,0);
len=ntohl(len);
char *buf=(char *)malloc(len+1);
int res=readn(fd,buf,len);
if(res<len){
fprintf(stderr,"接收失败\n");
free(buf);
return -1;
}
buf[len]='\0';
*msg=buf;
return len;
}
运行效果:
将家目录下的1.png上传到服务器,在由其他客户端将1.png下载到其所在目录,diff比较这两个1.png,无现象表示两个文件内容相同。