欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux系统下通过TCP可下载文件的客户端、服务端

程序员文章站 2022-03-04 08:53:50
...

这是运行与Linux系统下的多线程并发服务器,可供多个客服端下载普通文件,大型MP3/MP4等文件。

功能通过终端命令进行操作



client端代码:



#include  <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/stat.h>
#include <fcntl.h>

//./clt  ip
int main(int argc, char ** argv)
{
    int ret ;
    int sfd;
	int fd;
    char buf[1024] = {0};
	char filebuf[1024]={0};
	char buf1[20]={0};

    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(ret < 0) {
        perror("socket");
        return -1;
    }

    struct sockaddr_in  s_addr;
    memset(&s_addr, 0, sizeof(s_addr));
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(8888);                    //服务器端口号,要转换成网络字节序
    s_addr.sin_addr.s_addr  = inet_addr(argv[1]);     //服务器地址, 要转换成网络字节序
    //连接服务器
    ret = connect (sfd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr));
    if(ret < 0) {
        perror("socket");
        return -1;
    }


    char input[100];

    while(1) {

        printf("please input data:\r\n");
        ret =  read(0, input, 50);
        if(ret < 0) {
            perror("send");
            return -1;
        }
        input[ret-1] = '\0';

        //发送数据给客户端
        ret = send(sfd, input, strlen(input), 0);
        if(ret < 0) {
            perror("send");
            return -1;
        }
		memset(filebuf,0,sizeof(filebuf));
		strcat(filebuf,"./");
		strcat(filebuf,input);
		printf("%s\r\n",filebuf);
		fd = open(filebuf,  O_WRONLY | O_APPEND | O_CREAT, 0666);//
			if(fd<0)
				{
					perror("open");
			}
		while(1)
			{	
			memset(buf,0,1024);
        //接收数据,如果客户端没有发送数据会阻塞在这里
        ret = recv(sfd, buf, 1024, 0);
        if(ret < 0  ) {
            perror("recv ");
            return -1;
        }
		 if(ret == 0) {
            printf("child thread tid==%lu exit\r\n", pthread_self());
			break;
        }
	buf[ret]='\0';

		if(memcmp(buf,"ok",2)==0)
		{
			printf("------download finshed----\r\n");
				break;
		}
		write(fd, buf, 1024);
		memset(buf,0,1024);
		
		
		
		
			}	
		close(fd);
    }
    close(sfd);
    return 0;
}


service端带代码:


//多线程并发服务器
#include  <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

struct server_info {
    int cfd;                         //通信套接字
    struct sockaddr_in     c_addr;   //存放客户端地址
};


void * function(void*arg)   ;


int main(int argc, char ** argv)
{
    int ret ;
    int sfd, cfd;
    pthread_t  tid;  //线程id


    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(ret < 0) {
        perror("socket");
        return -1;
    }


    //让服务器断开后重启连接不会报地址被占用的错误
    int reuse = 1;
    ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));


    struct sockaddr_in  s_addr;
    memset(&s_addr, 0, sizeof(s_addr));
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(8888);                    //服务器端口号,要转换成网络字节序
    //s_addr.sin_addr.s_addr =  inet_addr("192.168.1.123");//服务器地址, 要转换成网络字节序
    s_addr.sin_addr.s_addr  =  0;    //服务器一般填充0,这样程序可以任意IP的计算中运行。
    ret  =  bind(sfd, ( struct sockaddr*)&s_addr, sizeof(struct sockaddr));
    if(ret < 0) {
        perror("bind");
        return -1;
    }




    ret = listen(sfd, 10);
    if(ret < 0) {
        perror("listen");
        return -1;
    }




    struct sockaddr_in  c_addr;
    int  addrlen;
    memset(&c_addr, 0, sizeof(c_addr));


    while(1) {


        //等待连接
        cfd = accept(sfd, (struct sockaddr*)&c_addr, &addrlen);
        if(cfd < 0) {
            perror("accept ");
            return -1;
        }


        //创建线程独立数据结构空间
        //每个线程应该有独立的cfd,c_add结构,malloc是在堆空间中分配数据
        struct server_info *tinfo = malloc(sizeof(struct server_info));
        memset(tinfo, 0, sizeof( struct server_info));
        tinfo->cfd    = cfd;


        tinfo->c_addr = c_addr;
        ret = pthread_create(&tid, NULL, function, (void*)tinfo) ; //创建线程
        if(ret != 0) {
            perror("pthread_create ");
            free(tinfo);
            return -1;
        }
    }


    close(sfd);


    return 0;
}






//写一个线程函数
//假设传递进来是 struct server_info * ,则把arg转换回来
void * function(void*arg)
{
    int ret;
	int fd;
	int fr;
    char buf[1025] = {0};
	char filebuf[1024]={0};
	char fbuf[]={"ok"};
	//int fbuf[1]={52};
    struct server_info * info = ( struct server_info *)arg;


    pthread_detach(pthread_self());       //把本线程变成分离式线程


    //char *inet_ntoa(struct in_addr in);
    printf("One client is connected:ip:%s:%d\r\n",
           inet_ntoa(info->c_addr.sin_addr), ntohs(info->c_addr.sin_port));


    while(1) {
        //接收数据,如果客户端没有发送数据会阻塞在这里
        printf("=========\r\n");
        ret = recv(info->cfd, buf, 100, 0);
        if(ret < 0) {
            perror("recv ");
            break;
        }


        //ret==0;说明连接已经断开,子进程 要终止
        if(ret == 0) {
            printf("child thread tid==%lu exit\r\n", pthread_self());
            //资源释放
            close(info->cfd);
            free(info);            
            pthread_exit(NULL);
        }


       buf[ret] = '\0';
        printf("C---> S : %s \r\n", buf);
		memset(filebuf,0,sizeof(filebuf));
		strcat(filebuf,"./");
		strcat(filebuf,buf);
		//strcat(filebuf,".mp3");
		//strcat(filebuf,".txt");
		printf("%s\r\n",filebuf);
		fd = open(filebuf,  O_RDONLY);
		if(fd<0)
			{
				perror("open");
		}
		while(1)
		{
			memset(buf,0,1024);
			fr=read(fd, buf, 1024);
			if(fr==0)
			{
				printf("file read over\r\n");
				sleep(1);//不加延时会不能跳出来
					ret = send(info->cfd, fbuf, 2, 0);
					//printf("%d\r\n",strlen(fbuf));
			        if(ret < 0) {
			            perror("send");
			            break;
			        	}
					break;
				
	        
			}
			else 
				{
				//发送数据给客户端
					
	        ret = send(info->cfd, buf, fr, 0);
	        if(ret < 0) {
	            perror("send");
	            break;
	        	}
				
				}
			
		}
		//perror("open------------------");
		close(fd);
    }


    //资源释放
    close(info->cfd);
    free(info);
    pthread_exit(NULL);


}