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

这是运行与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);


}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值