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