利用多线程并发模型,实现TCP文件传输

4 篇文章 0 订阅
2 篇文章 0 订阅

多线程的进程和单线程的进程比较

更高的效率:上下文切换的额外开销减少

上下文切换:线程切换需要执行的指令

同一进程中的两个线程比不同进程中的两个线程切换要快

进程内的线程切换不用改变虚拟存储器的映射

 

共享存储:

并发服务器中的多个副本需要相互通信或者访问共享的数据

利用线程容易构造监控系统

  

但是

由于线程间共享存储和进程状态,一个线程的动作可能对同一个进程内的其他线程产生影响。

两个线程如果同一时刻访问同一个变量,会产生相互干扰

调用一个静态的数据项的库函数不是线程安全(thread safe)的,覆盖将会导致错误

缺乏健壮性,一个线程出错,服务器将会终止整个进程 

 

server.c

// tcp_server_thread.c

/* TCPmtechod.c - main, TCPechod, prstats */
 
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
 
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/errno.h>
#include <netinet/in.h>
 
#define QLEN  32/* maximum connection queue length*/
#define BUFSIZE 4096
 
#define INTERVAL 5/* secs */
 
struct {
 
	pthread_mutex_t st_mutex;
	unsigned int st_concount;
	unsigned int st_contotal;
	unsigned long st_contime;
	unsigned long st_bytecount;
 
}stats;
 
void prstats(void);
int TCPechod(int fd);
//interrexit(const char *format, ...);
int passiveTCP(int qlen);
 
int main(int argc, char *argv[])
{
 
	pthread_t th;
	pthread_attr_t ta;
	struct sockaddr_in fsin;/* the address of a client*/
	unsigned int alen;/* length of client's address*/
	int msock;/* master server socket*/
	int ssock;/* slave server socket*/
 
	msock = passiveTCP(QLEN);
 
	(void) pthread_attr_init(&ta);
	(void) pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED);
	(void) pthread_mutex_init(&stats.st_mutex, 0);
 
	if (pthread_create(&th, &ta, (void * (*)(void *))prstats, 0) < 0)
		printf("pthread_create error\n");
 
	while (1) {
 
		alen = sizeof(fsin);
		ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
		if (ssock < 0) {
			printf("accept error");
		}else{
			printf("accpet successful\n");
		}
		if(pthread_create(&th, &ta, (void * (*)(void *))TCPechod, (void *)ssock) < 0)
			printf("pthread_create error");
 
	}
}
 
int passivesock(/*const char* service,*/ const char *transport, int qlen){
        struct servent *pse;
        struct protoent *ppe;
        struct sockaddr_in sin;
        int s, type;

        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = INADDR_ANY;
		sin.sin_port = htons(8888);

        type = SOCK_STREAM;

        s = socket(PF_INET, type, 0/*ppe->p_proto*/);
        if(s < 0){
            printf("can not create socket...");
        }

        if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
            printf("can not bind the port...");
        }

        if(type == SOCK_STREAM && listen(s, qlen) < 0)
            printf("can not listen the port...");
	return s;
}

int passiveTCP(int qlen){
        return passivesock(/*service, */"tcp", QLEN);
}

int processFile(int ssock){
	char filename[100];
    char filepath[100];

	FILE *fp;
	char *buffer;
    int fileTrans;

    memset(filename,'\0',sizeof(filename));
    memset(filepath,'\0',sizeof(filepath));

    buffer = (char *)malloc(sizeof(char)*BUFSIZE);
    bzero(buffer,BUFSIZE);
	int lenfilepath = recv(ssock,filepath,100,0);
    printf("filepath :%s\n",filepath);
    if(lenfilepath < 0){
       printf("recv error!\n");
	   return 1;
    }else{
       int i=0,k=0;  
       for(i=strlen(filepath);i>=0;i--)  
       {  
           if(filepath[i]!='/'){  
                k++;  
            }else 
				break;    
        }
        strcpy(filename,filepath+(strlen(filepath)-k)+1);   
     }
     printf("filename :%s\n",filename);
     fp = fopen(filename,"w");
     if(fp!=NULL){
        while(fileTrans = recv(ssock,buffer,BUFSIZE,0)){
             if(fileTrans<0){
                 printf("recv error!\n");
                 break;
                }
              int writelength = fwrite(buffer,sizeof(char),fileTrans,fp);
              if(writelength < fileTrans){
                  printf("write error!\n");
                  break;
               }
			   (void) pthread_mutex_lock(&stats.st_mutex);
			   stats.st_bytecount += fileTrans;
			   (void) pthread_mutex_unlock(&stats.st_mutex);
			   bzero(buffer,BUFSIZE); 
        }
        printf("recv finished!\n");
        fclose(fp);
     }else{
       printf("filename is null!\n");
	   return 1;
	  }

	  //kill(spid, SIGTERM);
	  return 0;

}
int TCPechod(int fd)
{
 
	time_t start;
	char buf[BUFSIZ];
	int cc;
 
	start = time(0);
	(void) pthread_mutex_lock(&stats.st_mutex);
	stats.st_concount++;
	(void) pthread_mutex_unlock(&stats.st_mutex);
	processFile(fd);
 
	(void) close(fd);
	printf("the process is killed\n");
	(void) pthread_mutex_lock(&stats.st_mutex);
	stats.st_contime += time(0) - start;
	stats.st_concount--;
	stats.st_contotal++;
	(void) pthread_mutex_unlock(&stats.st_mutex);
	return 0;
 
}
 
void prstats(void)
{
 
	time_t now;
 
	while (1) {
 
	(void) sleep(INTERVAL);
 
	(void) pthread_mutex_lock(&stats.st_mutex);
	now = time(0);
	(void) printf("--- %s", ctime(&now));
	(void) printf("%-32s: %u\n", "Current connections", stats.st_concount);
	(void) printf("%-32s: %u\n", "Completed connections", stats.st_contotal);
	if (stats.st_contotal) {
 
	(void) printf("%-32s: %.2f (secs)\n", "Average complete connection time",
	(float)stats.st_contime /
	(float)stats.st_contotal);
	(void) printf("%-32s: %.2f\n","Average byte count",(float)stats.st_bytecount /
	(float)(stats.st_contotal + stats.st_concount));
 
	}
	(void) printf("%-32s: %lu\n\n", "Total byte count", stats.st_bytecount);
	(void) pthread_mutex_unlock(&stats.st_mutex);
	}
 
}

client.c

//tcp_client.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <memory.h> 
#include <stdlib.h>  //for malloc
#define BUFFER_SIZE 1024
int main()
{
    int sockcd;
    struct sockaddr_in server;
    char filepath[100];//file to translate
    FILE *fp;
    int lenpath; //filepath length
    char *buffer;//file buffer
    int fileTrans;
    buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
    bzero(buffer,BUFFER_SIZE); 
    //memset(buffer,0,sizeof(buffer));

    if((sockcd = socket(AF_INET,SOCK_STREAM,0))<0)
    {
        printf("socket build error!\n");
    }
    memset(&server,0,sizeof(server));
    server.sin_family= AF_INET;
    server.sin_port = htons(8888);
    if(inet_pton(AF_INET,"127.0.0.1",&server.sin_addr)<0)
    {
        printf("inet_pton error!\n");
    }

    if(connect(sockcd,(struct sockaddr*)&server,sizeof(server))<0)
    {
        printf("connect error!\n");
    }//connect with server 

    printf("file path:\n");
    scanf("%s",filepath);//get filepath

    fp = fopen(filepath,"r");//opne file
    if(fp==NULL)
    {
        printf("filepath not found!\n");
        return 0;

    }
    printf("filepath : %s\n",filepath);
    lenpath = send(sockcd,filepath,strlen(filepath),0);// put file path to sever 
    if(lenpath<0)
    {
        printf("filepath send error!\n");
    }
    else
    {
        printf("filepath send success!\n");
    }
    sleep(1);
    while((fileTrans = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
    {
        printf("fileTrans =%d\n",fileTrans);
        if(send(sockcd,buffer,fileTrans,0)<0)
        {
            printf("send failed!\n");
            break;      
        }
        bzero(buffer,BUFFER_SIZE); 
        //memset(buffer,0,sizeof(buffer));  
    }
    fclose(fp);

    close(sockcd);
    return 0;
}

运行结果:

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值