TCP文件传输服务器

服务器实现功能:利用网络编程实现上传下载文件,显示服务器和客户端所在路径所有文件;利用多线程实现并发服务器。
思路:1.服务器首先要设置好IP,端口等网络编程要使用到的信息;然后通过while循环实现循环接受客户端的连接,并且连接后创建线程,实现并发跳转到线程处理函数;其次在线程处理函数里面使用switch语句来判断客户端的请求;最后判断客户端的请求以后调用相应的函数进行处理。
2.客户端首先也是要设置IP,端口等信息,然后通过while循环显示可用功能并且循环处理客户请求;然后在while循环里面使用switch语句来判断客户的请求。最后调用相应的函数进行处理。
服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>

void *thread_fun(void *);//线程处理函数
void list(long);//显示服务器所在路径的文件函数
void download(long);//下载文件函数
void upload(long);//上传文件函数

int main(int argc, char* argv[])
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0),connfd;//创建套接字,使用IPV4地址通信并且使用流式套接字
    if(sockfd==-1)
    {
        perror("socket");
        return -1;
	}
    struct sockaddr_in ser,cli;//该结构体存储地址等信息
    ser.sin_family=AF_INET;//设置IPV4通信
    ser.sin_port=htons(8888);//设置端口号
    ser.sin_addr.s_addr=inet_addr("0.0.0.0");//会自动匹配可用IP,也可换成自己电脑的IP
    socklen_t ser_len=sizeof(ser);//ser的大小
    if(-1==bind(sockfd,(struct sockaddr*)&ser,ser_len))//绑定套接字
    {
        perror("bind");
        close(sockfd);
        return -1;
    }
    if(-1==listen(sockfd,10))//监听是否有客户端连接
    {
        perror("listen");
        close(sockfd);
        return -1;
    }
    socklen_t cli_len=sizeof(cli);//cli的大小,用来存储连接客户端的信息
    char s[100];
    while(1)
{
        connfd=accept(sockfd,(struct sockaddr*)&cli,&cli_len);//接受客户端的连接
        pthread_t tid;//线程ID
        if(0!=pthread_create(&tid,NULL,thread_fun,(void *)(long)connfd))//创建线程,调用线程处理函数并且给线程处理函数传擦(通信套接字)
        {
            perror("pthread_create");
            close(sockfd);
            return -1;
        }
        pthread_detach(tid);//回收线程资源
    }
    close(connfd);
    close(sockfd);
    return 0;
}

void *thread_fun(void *arg)
{
    char buf[20];
    long connfd=(long)arg,flag=1;
    while(flag)//循环读取客户端的请求,并且调用相应的函数进行处理
    {
        read(connfd,buf,sizeof(buf));
        switch(buf[0])
        {
            case 'q':close(connfd);
                     pthread_exit(0);
                     flag=0;
                     break;
            case 'l':list(connfd);
                     break;
            case 'd':list(connfd);
                     download(connfd);
                     break;
            case 'u':upload(connfd);
                     break;
        }
    }
}

void list(long connfd)
{
    char buf[128];
    DIR *fp=opendir(".");//打开当前目录
    struct dirent* file;
    while(file=readdir(fp))//读取当前目录下的文件并且将文件的参数传递给file存储,然后会自动读取下一个文件,如果该目录下文件读取完则返回NULL
    {
        strcpy(buf,file->d_name);//将文件的名字复制到buf中
        write(connfd,buf,sizeof(buf));//通过通信套接字将文件名传递给客户端
    }
    write(connfd,"NULL",5);//读取完成后给客户端发送NULL代表读取完成
    return;
}
void download(long connfd)
{
    char buf[128];
    long size;//存储文件的大小
    int fd=-1;//文件描述符
    read(connfd,buf,sizeof(buf));//接收客户端发送过来的文件名
    fd=open(buf,O_RDONLY);//open打开文件用于后续的操作
    FILE *fp=fopen(buf,"r");//fopen打开文件用于计算文件大小
    fseek(fp,0,SEEK_END);
    size=ftell(fp);
    sprintf(buf,"%ld",size);//利用sprintf将文件大小转换成字符串传递给客户端,用于判断文件是否传输完成,也可用标志位完成
    write(connfd,buf,sizeof(buf));
    fclose(fp);

    int ret=0;
    while(ret=read(fd,buf,sizeof(buf)))//读取文件内容,若读取完成则返回0
    {
        write(connfd,buf,ret);//将读取的内容传递给客户端
    }
    close(fd);
    return;
}
void upload(long connfd)
{
    char buf[128];
    read(connfd,buf,sizeof(buf));//接收客户端需要上传的文件名字
    int fd=open(buf,O_WRONLY | O_CREAT,400);//以只写方式打开需要上传的文件,若没有则创建且赋予创建的文件读写的权限
    read(connfd,buf,sizeof(buf));//接收文件的大小
    int size=atoi(buf),ret=0;//将文件的大小转为整型数字
    while(1)
    {
        ret+=read(connfd,buf,sizeof(buf));//ret为读取到传递过来的数据大小
        write(fd,buf,ret);
        if(ret==size)//若读取到的数据大小与文件大小一致,则代表读取完成跳出循环
            break;
    }
    close(fd);
    return;
}

客户端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>

void list(int);
void download(int);
void upload(int);

int main(int argc, char* argv[])
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0),connfd;
    if(sockfd==-1)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in ser;
    ser.sin_family=AF_INET;
    ser.sin_port=htons(8888);
    ser.sin_addr.s_addr=inet_addr("192.168.44.128");//设置服务器的可用IP
    socklen_t len=sizeof(ser);
    if(connect(sockfd,(struct sockaddr*)&ser,len))//主动请求连接服务器
    {
        perror("connect");
        close(sockfd);
        return -1;
    }
    char str[10];
    int flag=1;
    while(flag)//循环接收客户的请求并且发送给服务器
    {
        printf("*************请输入以下选项**************\n");
        printf("l :显示目录下的文件           q :退出\n");
        printf("d :下载文件                   u :上传文件\n");
        printf("*****************************************\n");
        scanf("%s",str);
        switch(str[0])
        {
            case 'q':write(sockfd,"q",2);
                     flag=0;
                     break;
            case 'l':write(sockfd,"l",2);
                     list(sockfd);
                     break;
            case 'd':write(sockfd,"d",2);
                     list(sockfd);
                     download(sockfd);break;
            case 'u':write(sockfd,"u",2);
                     upload(sockfd);
                     break;
            default :printf("输入错误,请重新输入\n");
                     break;
       }
    }
    close(sockfd);
    return 0;
}


void list(int sockfd)
{
    char buf[128];
    while(1)//循环读取从服务器发送过来的文件名称然后打印,直至读取到NULL代表读取完成
    {
        read(sockfd,buf,sizeof(buf));
        if(strcmp(buf,"NULL")==0)
            break;
        printf("filename:%s\n",buf);
    }
    printf("以上是服务器路径所有文件\n\n");
    return;
}
void download(int sockfd)
{
    char buf[128];
    printf("请输入需要下载的文件名\n");
    scanf("%s",buf);
    write(sockfd,buf,sizeof(buf));//将需要下载的文件名发送给服务器
    int fd=open(buf,O_WRONLY | O_CREAT,400);
    read(sockfd,buf,sizeof(buf));//接收文件的大小
   int size=atoi(buf),ret=0;
    while(1)
    {
        ret+=read(sockfd,buf,sizeof(buf));
        write(fd,buf,ret);
        if(ret==size)
            break;
    }
    printf("下载完成\n\n");
    close(fd);
    return;
}
void upload(int sockfd)
{
    DIR *f=opendir(".");
    struct dirent* file;
    while(file=readdir(f))
    {
        if(file->d_type=='d')
            continue;
        printf("filename:%s\n",file->d_name);
    }
    closedir(f);

    char buf[128];
    printf("请输入需要上传的文件名\n");
    scanf("%s",buf);
    write(sockfd,buf,sizeof(buf));
    FILE *fp=fopen(buf,"r");
    int fd=open(buf,O_RDONLY),ret=0;
    fseek(fp,0,SEEK_END);
    long size=ftell(fp);
    sprintf(buf,"%ld",size);
    write(sockfd,buf,sizeof(buf));
    fclose(fp);
    while(ret=read(fd,buf,sizeof(buf)))
    {
        write(sockfd,buf,ret);
    }
    printf("上传完成\n\n");
    close(fd);
    return;
}

结果截图
服务器和客户端在不同的路径,并且文件也有所区别
在这里插入图片描述
显示服务器所在路径的所有文件
在这里插入图片描述
下载服务器所在路径的文件
在这里插入图片描述
上传文件和退出
在这里插入图片描述
运行结果
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值