Linux下使用Socket编程的文件上传例子

1 Server端与Client端公用的代码库:包含 tcp.h,tcp.c , file.h, file.c , tpool.h, tpool.c

//tcp.h 头文件 

#ifndef TCP_H_
#define TCP_H_
#include<stdio.h>
#include<stdlib.h>           /*exit()*/
#include<sys/socket.h>      /*bind(),socket()...*/


#include<arpa/inet.h>      /*inet_aton(),inet_ntoa(),inet_pton()...*/
#include<netinet/in.h>    /* struct sockaddr_in, htons() ...*/
#include<string.h>       /*bzero()*/
#include<unistd.h>      /* read(),write(),fork()*/
#include<errno.h>      /*errno*/
#include<signal.h>
#include<sys/wait.h>
#include<fcntl.h>  /*open(),creat()*/


#include<sys/select.h>
#include<sys/time.h>
#include<sys/stat.h> /* mkdir*/


// #include <stdio.h> 
// #include <stdlib.h> 
// #include <unistd.h> 
#include <sys/types.h> 
#include <pthread.h> 
#include <assert.h> 




#define MAXLINE 4096
#define PORT  9887
#define REMOTE_IP "127.0.0.1" 
#define LISTENQ 1024
#define MAX 256
	
#define PATH "./tmp" 
#define PATH2 "./tmp/\0"	


#define SA struct sockaddr
#define max(a,b) ((a)>(b)?(a):(b))


typedef void Sigfunc(int);


#endif
// tcp.c  tcp 读写函数,readn, writen

#include "tcp.h"

Sigfunc *Signal(int sig,Sigfunc *func)
{
	struct sigaction act,oact;  /* storage size is unknow, why???*/
	
	act.sa_handler=func;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	
	if(sig==SIGALRM)
	{
#ifdef SA_INTERRUPT
	act.sa_flags|=SA_INTERRUPT;
#endif
	}
	else
	{
#ifdef SA_RESTART
	act.sa_flags|=SA_RESTART;
#endif
	}
	if(sigaction(sig,&act,&oact)<0)
		return(SIG_ERR);
	return(oact.sa_handler);
}

ssize_t      /* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)   /* <sys/uio.h>  the same below*/
{
	size_t nleft;
	ssize_t nread;
	char *ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;  /* and call read() again */
			else
				return(-1);
		} else if (nread == 0)
			break;    /* EOF */

			nleft -= nread;
			ptr   += nread;
	}
	return(n - nleft);  /* return >= 0 */
}
ssize_t writen(int fd, const void *vptr, size_t n)
{
	size_t  nleft;
	ssize_t  nwritten;
	const char *ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;  /* and call write() again */
			else
				return(-1);   /* error */
		}

		nleft -= nwritten;
		ptr   += nwritten;
	}
	return(n);
}

// fil.h 文件传输格式

#ifndef FILE_H_
#define FILE_H_

/* 处理上传单个文件的功能*/

/*
#define SEND_FILE "SEND_FILE" 
#define REQ_FILE  "REQU_FILE"
#define READY_OK "REDY_OK"
#define SEND_FIN "SEND_FIN"
#define RESP_FIN "RESP_FIN"
*/
#define CMD_LEN 6
#define REC_OK "REC_OK"  /*接收成功*/
#define REC_FAIL "R_FAIL"/* 接受失败*/

#define FD_NOT_SET '0'
#define FD_OK '1'

#define SUCCESS 1
#define FAILED 0

typedef struct net_file
{
	unsigned int  filename_size;
	char filename[MAX];
	unsigned long filedata_size;
	int fd;
	char fd_stat; 
	char buf[MAXLINE];
// 	unsigned char mark; 
// 	struct net_file *next;
}netfile_t;


#endif

// file.c 

#include "tcp.h"
#include "file.h"



/* filename:end with '\0' */
int receive_net_file(int sockfd,netfile_t *netfile) 
{
	int read_bytes=0;
	int nready=0;
	char buf[MAXLINE];
	char path[256];

	
	if(netfile==NULL)
		return FAILED;
	bzero(netfile,sizeof(netfile_t)); 
	/*reveive file_name_size */
	if(readn(sockfd,&netfile->filename_size,sizeof(unsigned int))==0) /* character sequence ?????*/
	{
		printf("client exit 1 \n");
		return FAILED;
	}
	printf("file_name_size:%u\n",netfile->filename_size);
	
	if(readn(sockfd,netfile->filename,netfile->filename_size)==0)
	{
		printf("client exit 2 \n");
		return FAILED;
	}
	netfile->filename[netfile->filename_size]='\0';
	printf("filename:%s \n",netfile->filename);
	
	if(readn(sockfd,&netfile->filedata_size,sizeof(unsigned long))==0)
	{
		printf("client exit  3\n");
		return FAILED;
	}
	printf("filedata_size:%lu \n",netfile->filedata_size);
	
	/* creat a file */
	
	strcpy(path,PATH2);
	strcat(path,netfile->filename);
	printf("path:%s\n",path);
	if((netfile->fd=open(path,O_RDWR|O_CREAT|O_TRUNC,0644))==-1)
	{
		perror("creat file fialed:");
		netfile->fd_stat=FD_NOT_SET;
		writen(sockfd,REC_FAIL,CMD_LEN); /*返回失败信息*/
		return FAILED;
	}
	
	
	/* no data ******/
// 	if(netfile->filedata_size==0){
// 	close(netfile->fd);
// 	netfile->fd_stat=FD_NOT_SET;
// 	return -1;
// 	}
	
	netfile->fd_stat=FD_OK;
	
	while(read_bytes<netfile->filedata_size)
	{
		bzero(buf,MAXLINE);
		if(netfile->filedata_size-read_bytes>MAXLINE)
			nready=readn(sockfd,buf,MAXLINE);
		else  /* 最后不够maxline 整数的字节*/
			nready=readn(sockfd,buf,netfile->filedata_size-read_bytes);
		if(nready!=write(netfile->fd,buf,nready)) /*写入文件*/
		{
			printf("error\n");
			writen(sockfd,REC_FAIL,CMD_LEN);
			return FAILED;
		}
		read_bytes+=MAXLINE;
	}
	writen(sockfd,REC_OK,CMD_LEN);
	netfile->fd_stat=FD_NOT_SET;
	close(netfile->fd);
	return SUCCESS;
}

void close_net_file(netfile_t *netfile)
{
	if(netfile==NULL)
		return;
	if(netfile->fd_stat==FD_OK)
	{
		netfile->fd_stat=FD_NOT_SET;
		close(netfile->fd);
	}
}	



	

// tpool.h 线程池

ifndef TPOOL_H_
#define TPOOL_H_

#define BUSY_THRESHOLD 0.5	//(busy thread)/(all thread threshold)
#define MANAGE_INTERVAL 5	//tp manage thread sleep interval
typedef struct worker 
{     
	void *(*process) (void *arg); 
	void *arg;  /* connection socket */
	struct worker *next; 
}CThread_worker; 

typedef struct thread_info
{
	pthread_t threadid;
	int busy;/* 1 is busy,0 is idle */
}thread_info_t;
/*threadpool structure */
typedef struct 
{ 
	pthread_mutex_t queue_lock; 
	pthread_cond_t queue_ready; 
	
	CThread_worker *queue_head; /* all tasks which are waiting */

	int shutdown; 	          /* whether destroy the CThread_pool */
	thread_info_t *thread_queue;      /*thread queue */
	pthread_t manage_thread_id; 
	int min_thread_num;     /* minmum number of threads */
	int max_thread_num;  	/* maxnum number of threads */
	int cur_thread_num;
	int cur_queue_size;    /* thread's number in the waiting-queue */
} CThread_pool; 
#endif

// tpool.c

#include "tcp.h"
#include "tpool.h"
/* 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <pthread.h> 
#include <assert.h>
*/ 


int pool_add_worker (void *(*process) (void *arg), void *arg); 
void *thread_routine (void *arg); 
int delete_thread();
int get_id_by_threadid( int threadid);
int  get_tp_status();
void *manage_routine(void *arg);

static CThread_pool *pool = NULL; 

void pool_init (int min_thread_num,int max_thread_num) 
{ 
	pool = (CThread_pool *) malloc (sizeof (CThread_pool)); 
	pthread_mutex_init (&(pool->queue_lock), NULL); 
	pthread_cond_init (&(pool->queue_ready), NULL); 
	pool->queue_head = NULL; 
	pool->max_thread_num = max_thread_num; 
	pool->cur_queue_size = 0; 
	pool->cur_thread_num=min_thread_num;
	pool->min_thread_num=min_thread_num;
	pool->shutdown = 0; 
	
	pool->thread_queue = (thread_info_t *) malloc (max_thread_num * sizeof (thread_info_t)); 
	int i = 0; 
	for (i = 0; i < min_thread_num; i++) 
	{  
		pthread_create(&(pool->thread_queue[i].threadid), NULL, thread_routine, NULL); 
		pool->thread_queue[i].busy=0;
	} 
	pthread_create(&(pool->manage_thread_id),NULL, manage_routine, NULL);
} 

int add_thread()
{
// 	pthread_mutex_lock (&(pool->queue_lock));
	if(pool->cur_thread_num<pool->max_thread_num)
	{
		printf("**********pool->cur_thread_num:%d\n",pool->cur_thread_num);
// 		pthread_mutex_unlock (&(pool->queue_lock)); 
		pool->thread_queue[pool->cur_thread_num].busy=0;
		pool->cur_thread_num++;
		pthread_create (&(pool->thread_queue[pool->cur_thread_num].threadid), NULL, thread_routine, NULL); 
		printf ("thread %lu is added\n", pool->thread_queue[pool->cur_thread_num].threadid); 
		return 1;
	}
// 	else
// 		pthread_mutex_unlock (&(pool->queue_lock)); 
	return 0;
	
}
int delete_thread(){
	int i;
// 	pthread_mutex_lock (&(pool->queue_lock));
	//current thread num can't < min thread num or if last thread is busy, do nothing
	if(pool->cur_thread_num <= pool->min_thread_num)
	{
// 		pthread_mutex_unlock (&(pool->queue_lock)); 
		return 0;
	}
	for(i=0;pool->thread_queue[i].busy!=0 && i<pool->cur_thread_num;i++){};
	if(i<pool->cur_thread_num)
	{
// 		kill(pool->thread_queue[i].threadid, SIGKILL);
		pthread_join (pool->thread_queue[i].threadid, NULL); 
		printf ("thread %lu is Killed\n", pool->thread_queue[i].threadid); 
	}
	pool->cur_thread_num--;
// 	pthread_mutex_unlock (&(pool->queue_lock)); 
	return 1;
}
	
int get_id_by_threadid( int threadid){
	int i;
	for(i=0;i<pool->cur_thread_num;i++){
		if(threadid == pool->thread_queue[i].threadid)
			return i;
	}

	return -1;
}
int  get_tp_status(){
	float busy_num = 0.0;
	int i;
        
	if(pool->cur_thread_num==pool->min_thread_num)
		return 1;
	//get busy thread number
	for(i=0;i<pool->cur_thread_num;i++){
		if(pool->thread_queue[i].busy)
			busy_num++;
	}

	//0.2? or other num?
	if(busy_num/(pool->cur_thread_num) < BUSY_THRESHOLD)
// 	if(pool->cur_thread_num>pool->min_thread_num+1)
		return 0;//idle status
	else
		return 1;//busy or normal status	
}	

int 
pool_add_worker (void *(*process) (void *arg), void *arg) 
{ 
	/**/ 
	CThread_worker *newworker = (CThread_worker *) malloc (sizeof (CThread_worker)); 
	newworker->process = process; 
	newworker->arg = arg; 
	newworker->next = NULL;
	
	pthread_mutex_lock (&(pool->queue_lock)); 
	CThread_worker *member = pool->queue_head; 
	if (member != NULL)  /* add member to the end of the pool*/
	{ 
		while (member->next != NULL) 
			member = member->next; 
		member->next = newworker; 
	} 
	else 
	{ 
		pool->queue_head = newworker; 
	} 
	assert (pool->queue_head != NULL); 
	
	pool->cur_queue_size++; 
	pthread_mutex_unlock (&(pool->queue_lock)); 

	pthread_cond_signal (&(pool->queue_ready)); 
	return 0; 
} 



int pool_destroy () 
{ 
	if (pool->shutdown) 
		return -1;
	pool->shutdown = 1; 
	pthread_cond_broadcast (&(pool->queue_ready)); 
	int i; 
	for (i = 0; i < pool->cur_thread_num; i++) 
		pthread_join (pool->thread_queue[i].threadid, NULL); 
	free (pool->thread_queue); 
    	
	pthread_join (pool->manage_thread_id, NULL); 
	
	CThread_worker *head = NULL; 
	while (pool->queue_head != NULL) 
	{ 
		head = pool->queue_head; 
		pool->queue_head = pool->queue_head->next; 
		free (head); 
	} 
        
	pthread_mutex_destroy(&(pool->queue_lock)); 
	pthread_cond_destroy(&(pool->queue_ready)); 
    
	free (pool); 
	pool=NULL; 
	return 0; 
} 


void * thread_routine (void *arg) 
{ 
	printf ("starting thread %lu\n", pthread_self ()); 
	while (1) 
	{ 
		pthread_mutex_lock (&(pool->queue_lock)); 
		/**/ 
		while (pool->cur_queue_size == 0 && !pool->shutdown) 
		{ 
			printf ("thread %lu is waiting\n", pthread_self ()); 
			pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock)); 
		} 
     
		if (pool->shutdown) 
		{ 
			/*force to kill*/ 
			pthread_mutex_unlock (&(pool->queue_lock)); 
			printf ("thread %lu will exit\n", pthread_self ()); 
			pthread_exit (NULL); 
		} 
		printf ("thread %lu is starting to work\n", pthread_self ()); 
		/**/ 
		
		assert (pool->cur_queue_size != 0); 
		assert (pool->queue_head != NULL); 
         
		/**/ 
		CThread_worker *worker = pool->queue_head; 
		pool->queue_head = worker->next; 
		pool->cur_queue_size--; 
// 		pool->cur_thread_num++;
		pool->thread_queue[get_id_by_threadid(pthread_self ())].busy=1;/* lock ??**/
		pthread_mutex_unlock (&(pool->queue_lock)); 
		/**/ 
		
		(*(worker->process)) (worker->arg); 
		
		/* after processing */
		pthread_mutex_lock (&(pool->queue_lock)); 
		pool->thread_queue[get_id_by_threadid(pthread_self ())].busy=0;
// 		pool->cur_thread_num--;
		pthread_mutex_unlock (&(pool->queue_lock)); 
		
		free (worker); 
		worker = NULL; 
	} 
	/**/ 
	pthread_exit (NULL); 
} 
void *manage_routine(void *arg){
	int i;
	
	printf ("manage_thread %lu is starting to work\n", pthread_self ()); 
	sleep(MANAGE_INTERVAL);
	do{
// 		
		for(i=0;pool->thread_queue[i].busy!=0 && i<pool->cur_thread_num;i++){};
		pthread_mutex_lock (&(pool->queue_lock)); 
		if(i==pool->cur_thread_num && pool->cur_queue_size>0)
		{
			pthread_mutex_unlock (&(pool->queue_lock)); 
			add_thread();
		}
		else
			pthread_mutex_unlock (&(pool->queue_lock)); 
		
		sleep(MANAGE_INTERVAL);
		if(get_tp_status() == 0 ){
			do{
				if( !delete_thread() )
					break;
			}while(1);
		}
	}while(1);
}

2  Server端

server.c

#include "tcp.h"
#include "file.h"
/* using sigle process and the function--select() */	
/* existed question:denial-of-service */	

void * myprocess (void *arg) 
{ 
	int sockfd=*(int *)arg;
	netfile_t *netfile;
	netfile=(netfile_t*)malloc(sizeof(netfile_t));
	while(1)
	{
		if(receive_net_file(sockfd,netfile)==FAILED)
		{
			break;
		}
		printf("Receiving file:%s is finished \n",netfile->filename);
		close_net_file(netfile);
	} 
	free(netfile);
} 

/*初始化:创建上传后文件存放的文件夹*/
config_Init()
{

	if(opendir(PATH)==NULL)
	{
	 	if(mkdir(PATH,0755)<0) /*make a directory */
 			printf("\033[40;31m failed to create a folder \033[0m \n");/* if exist ,it generage a error */
	}
	else
		closedir(PATH);
}
 	

	
/* select () :detect  listen socket,generate a thread */	
void Listen () 
{
	int listenfd,connfd,maxfd;
	fd_set rset,allset;
	socklen_t clilen;
	char buff[16];
	struct sockaddr_in cliaddr,servaddr;
	
	listenfd=socket(AF_INET,SOCK_STREAM,0);
	
	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(PORT);
	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
	
	bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
	listen(listenfd,LISTENQ);
	printf("Server(PORT:%d) is Listening......\n",PORT);
	
	maxfd=listenfd;  /*initialize*/
	FD_ZERO(&allset);
	FD_SET(listenfd,&allset);
	
	for(;;)
	{
		printf("%s,%d,blocked in select()*****: \n",__FILE__,__LINE__); /*test*/
		
		rset=allset;
		select(maxfd+1,&rset,NULL,NULL,NULL); /*detect */

		if(FD_ISSET(listenfd,&rset))
		{
			clilen=sizeof(cliaddr);
			connfd=accept(listenfd,(SA*)&cliaddr,&clilen);
			printf("********connection from %s,port %d *******\n", /* a successful connection */
			       inet_ntop(AF_INET,&cliaddr.sin_addr,buff,sizeof(buff)),
			       ntohs(cliaddr.sin_port));
			
			pool_add_worker (myprocess, &connfd);/* add a connfd */ 
		}
	}
}
	
int main(void)
{
	config_Init();
	pool_init (3,5); /* the server will generate 10 threads */
	Listen();
	pool_destroy (); 
	return 0; 
}
		
		
	
	
	

makefile 文件

CC = gcc
XX = g++
CFLAGS = -Wall -O -g
TARGET = ./serv 

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

SOURCES = $(wildcard *.c )
OBJS = $(patsubst %.c,%.o,$(SOURCES))

$(TARGET) : $(OBJS)
	$(CC) $(OBJS) -o $(TARGET) -lpthread
	chmod a+x $(TARGET)

clean:
	rm -rf *.o
cleanall:
	rm -rf *.o serv *~

3 客户端代码


#include "tcp.h"
#include "file.h"
/* 目前只有1 功能*/
void input_files(int sockfd) 
{
	char fname[MAX];
	int i;
	char str[MAX];
	netfile_t *netfile;
	char choice[10];
	
	A:printf("--------------MENU------------------:\n");
	printf("Please input your choice:\n");
	printf(" 1: upload files, 2: download ,0:exit \n");
	printf("------------------------------------:\n");
	scanf("%s",choice);
		
	if(strcmp(choice,"1")==0)
	{
		do
		{
			printf("Please input filename:\n");
			scanf("%s",fname);/* should use fgets()*/
			
			netfile=(netfile_t*)malloc(sizeof(netfile_t));
			if(open_net_file(netfile,fname) ==-1)
			{
				printf("Filename is error,can't open \n");
				goto B;
			}
			if(sendfile(sockfd,netfile)==FAILED)
			{
				break;
			}
			close_net_file(netfile);
			
			B:printf("Do you want to transmit another file :(Y or N) \n");
			scanf("%s",str)	;	
		}while(strcmp(str,"Y")==0 || strcmp(str,"y")==0);
		free(netfile);
		goto A;
	}
}
	
	
int init()
{
	int sockfd;      
	struct sockaddr_in servaddr;
	
	if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
	{
		perror("socket errir");
		exit(1);
	}
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(PORT);
	
	if(inet_pton(AF_INET,REMOTE_IP,&servaddr.sin_addr)<=0)
	{
		perror("inet_pton error");
		exit(1);
	}
	/* servaddr.sin_addr.s_addr=inet_addr(REMOTE_IP); *****two methods */
	
	if(connect(sockfd,(SA*)&servaddr,sizeof(servaddr))<0)
	{
		close(sockfd);
		perror("connect error ");
		exit(1);
	}
	return sockfd;
}
	
int main(int argc,char **argv)
{
	input_files(init()); 
	exit(0);  /*退出*/
}
				

makefile 文件

CC = gcc
CFLAGS = -Wall -O -g
TARGET = ./cli 

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

SOURCES = $(wildcard *.c )
OBJS = $(patsubst %.c,%.o,$(SOURCES))

$(TARGET) : $(OBJS)
	$(CC) $(OBJS) -o $(TARGET) 
	chmod a+x $(TARGET)

clean:
	rm -rf *.o
cleanall:
	rm -rf *.o cli *~



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值