socket网络间通信传送任意大小和格式的文件

socket网络间通信传送任意格式和大小的文件

2012.4.17
by 韩大卫 @吉林师范大学 

一般的socket在网络间通信时,发个hello world 没有问题,但是一旦发送较大些的文件,大部分都会失败,

由于网络接口MTU的限制(一般mtu为1500),大些的文件只能分多次发送,这样就有几个问题需要要处理:

分几次发送?一次发送多大? 保存端的怎么保存?  

这些问题在我的代码中都得到了解决, 而且 server 端采用了多线程处理, 经过测试,发送端接收端都非常强悍!

一次性传送几百个M 的文件轻松愉快,而且各种反馈信息保证了调试,修改起来也非常容易。


 	修改IP地址和端口号,即可实现任意主机互联, 传送文件的大小和格式没有限制!
把服务器端保存为:socket_service.c   客户端:socket_client.c

编译时执行:

	gcc  socket_service.c -lpthread  -o server

	gcc  socket_client.c -o client

	
在server端执行  : #./server

client 端执行:   #./client  ./baby.jpg   MyBaby.jpg
	或者:	 #./client  Linux_driver.pdf    MyFile.pdf
	
	第一个参数是:client 要发送的文件,  第二个参数是 :server 要保存的文件名。
		
 即可把client 端当前目录下的Linux_driver.pdf   发送给server 端,  保存名为 Myfile.pdf,  路径可以自己定义。

但不能太长, 可以去修改 data.h 中的 struct  data 中的  filename ,filesavename 。 

	

*************************************************************************************/

/*******socket_service.c***************************/

#include "data.h"



int sockid;

pthread_t tid;


int fileopen;


__sighandler_t f_quit(void)
{

	printf("\nserver closed right now!!\n");
	close(sockid);
	close(fileopen);
	exit(0);


}


struct thread_para{

	int sockid;
	
	struct sockaddr_in addr;

	struct sockaddr_in fromaddr;

	struct data datarecv;
};


int main(int argc,char* argv[])
{
	

	signal(SIGINT,(__sighandler_t)f_quit);


	struct thread_para thread_do;

	memset(&thread_do,0,sizeof(thread_do));

	

	sockid = socket(AF_INET,SOCK_STREAM,0);
	
	if(sockid == -1)
		printf("socker create error!"),exit(-1);

	printf("sockid = %d\n",sockid);

	struct sockaddr_in addr;	
	
	addr.sin_family = AF_INET;

	addr.sin_port = htons(8888);
	
	//inet_aton("192.168.10.50",&addr.sin_addr);

	addr.sin_addr.s_addr = INADDR_ANY;

	int r = bind(sockid,(struct sockaddr*)&addr,sizeof(addr));

	if(r<0) 
		printf("bind error!,r=%s\n",strerror(errno)),exit(-1);
	
	printf("bind success!\n");



	if((r = listen(sockid,10))<0)
		printf("listen error!,r=%s\n",strerror(errno)),exit(-1);
	
	printf("listen successfully!\n");


	int fd,writelen,writelencount,recvlen,opnumber;
	
	struct sockaddr_in fromaddr;


	socklen_t len = sizeof(fromaddr);


	void* handler(void*);


	while(1){
		
		
		if( (fd = accept(sockid,(struct sockaddr*)&fromaddr,&len)) < 0 ){

			printf("accept error,errno = %s\n",strerror(errno)),exit(-1);
		} 

	
		printf("accept successfuluy!,new sockid=%d\n",fd);
	
	memset(&thread_do,0,sizeof(thread_do));
	
	thread_do.sockid = fd;

	thread_do.fromaddr = fromaddr;
	

	pthread_create(&tid,NULL,handler,&thread_do);


	}

}

void* handler(void* p)
{

	struct thread_para * thread_do = p;


	int writelen,writelencount,recvlen,opnumber;

	writelen = 0;

	writelencount = 0;	
	
	recvlen = 0;

	opnumber = 1;

	printf(" there are the data from %s :\n",inet_ntoa(thread_do->fromaddr.sin_addr) );
	

	do{


	memset(&thread_do->datarecv,0,sizeof(thread_do->datarecv));
	

	recvlen = recv( thread_do->sockid,&thread_do->datarecv,sizeof(thread_do->datarecv)-1,0);		
	
	if(recvlen<0) printf("recv error!,errro=%s\n",strerror(errno)),exit(-1);

	else if(recvlen == 0 ) 
		
		printf(" client has closed!\n");
	else

	
		printf("the filename from client:\n\t%s\n",thread_do->datarecv.filename);
		
		printf("the file save name:\n\t%s\n",thread_do->datarecv.filesavename);
	
		printf("the filelen =%d,the recvlen=%d,the filebuf = %d\n",
thread_do->datarecv.filelen,recvlen,sizeof(thread_do->datarecv.filebuf)-1 );

		printf("the shouldoplen = %d\n",thread_do->datarecv.shouldoplen);

		printf("the oplencount = %d\n",thread_do->datarecv.oplencount);
	

		umask(0);

		int fileopen = open((const char*)thread_do->datarecv.filesavename,
O_RDWR | O_CREAT | O_APPEND, S_IRWXU | S_IRWXG | S_IROTH );	
	
		if(fileopen<0){

			printf("fileopen error!,%s\n",strerror(errno)),exit(-1);
		
		}

		printf("file %s create and open successfully!\n",thread_do->datarecv.filesavename);



		if( (  writelen =  write(fileopen,thread_do->datarecv.filebuf,
thread_do->datarecv.shouldoplen)  ) <0 ){

			printf("write error!\n"),exit(-1);
		}

			 
		writelencount  += writelen;

		printf(" opnumber = %d,writelen=%d,writelencount=%d\n \n",opnumber++,writelen,writelencount);



		struct data_return data_r;
	
		data_r.writelen = writelen;
	
		data_r.writelencount = writelencount;	
		
		data_r.recvlen = recvlen;


		write(thread_do->sockid, &data_r ,sizeof(data_r));
		
		close(fileopen);
	

		}while( writelencount != thread_do->datarecv.filelen );

		
	
	

}	










/**************************************************************************************/

/*************socket_client.c**************************/


#include "data.h"


int sockid;



__sighandler_t f_quit(void)
{

        printf("\n client closed right now!!\n");
        close(sockid);
 
        exit(0);

  
}

void delay()
{
	int i ,j;
	for(i = 0;i<1000;i++)
		for(j=0;j<120000;j++);

}

int main(int argc,char* argv[])
{

	signal(SIGINT,(__sighandler_t)f_quit);

	sockid = socket(AF_INET,SOCK_STREAM,0);
	
	if(sockid==-1)printf("socket create error!"),exit(-1);

	struct sockaddr_in addr;

	memset(&addr,0,sizeof(addr));

	addr.sin_family = AF_INET;

	addr.sin_port = htons(8888);

	inet_aton("192.168.10.53",&addr.sin_addr);
	

	int r = connect(sockid,(struct sockaddr*)&addr,sizeof(addr));

	if(r<0)printf("connect error!\n"),exit(-1);

	printf("connect success!  \n");
	

	struct data datasent;
	
	memset(&datasent,0,sizeof(datasent));
	
	struct  data_return data_r;

	memset(&data_r,0,sizeof(data_r));

	strcpy(datasent.filename, argv[1]);
	
	strcpy(datasent.filesavename,argv[2]);

	int fd  = open(datasent.filename,O_RDWR);	

	if(fd<0)printf("open %s failed!\n",datasent.filename),exit(-1);
	
	datasent.filelen = lseek(fd,0,SEEK_END);
	
	lseek(fd,0,SEEK_SET);

	printf("open file %s success!,the fd = %d,file length  = %d\n",datasent.filename,fd,
datasent.filelen);

	datasent.oplencount = 0;

	int opnumber = 1;

	do{
	
	lseek(fd,datasent.oplencount,SEEK_SET);


	if( (datasent.filelen - datasent.oplencount ) >= ( sizeof(datasent.filebuf) - 1 ) ){
	
		datasent.shouldoplen = sizeof(datasent.filebuf) - 1 ;
	}

	else{
		datasent.shouldoplen = datasent.filelen -datasent.oplencount;	
	}

	memset(&datasent.filebuf,0,sizeof(datasent.filebuf));

	readdata(fd,&datasent,datasent.shouldoplen);

	datasent.oplencount += datasent.shouldoplen;

	sentdata(datasent);

	printf(" opnumber = %d,shouldoplen = %d ,datasent.oplencount = %d \n",
opnumber++,datasent.shouldoplen,datasent.oplencount);


	read(sockid,&data_r,sizeof(data_r));
	
	printf("server info:recvlen = %d, writelen = %d, writelencount = %d \n\n",
data_r.recvlen,data_r.writelen,data_r.writelencount);

//	delay();

	} while( datasent.filelen > datasent.oplencount );


	close(sockid);

	close(fd);				
								
}

int readdata(int fd,struct data* datasent,int len)
{
	int readlen;

	if((readlen = read( fd,datasent->filebuf,len ) )<0)
		printf("%m\n"),exit(-1);
	
	printf("read %s successfully ! readlen=%d\n",datasent->filename,readlen);


	//printf("%s\n",datasent->filebuf);

}


int sentdata(struct data datasent)
{

	int sendlen;	

	if((sendlen = send( sockid,&datasent,sizeof(datasent)-1,0 ))<0){
		printf("write error ,writelen=%d, sizeof(datasent): %d, error: %s\n",sendlen, sizeof(datasent), strerror(errno));
		exit(-1);
	}

	printf("file %s send successfully!,sendlen=%d\n",datasent.filename,sendlen); 


}














/*************************************************************************************/


/***********data.h*********************************/

#ifndef DATA_H
#define DATA_H

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


#include "data.h"


typedef  unsigned int uint;

struct data{


	char filename[30];

	char filesavename[30];
	
	uint filelen;

	uint shouldoplen;	
	
	uint oplencount;

	char filebuf[1301];


	
};


struct data_return {
		
	int writelen;
	
	int writelencount;
	
	int recvlen;
};





#endif


/*************************************************************************************/

转载于:https://my.oschina.net/handawei/blog/68109

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值