linuxC socket 发送和接收文件小例子

LINUX C 基于TCP/IP协议的SOCKET收发文件的小例子。

自已没事正看这方面的东西,感觉要想把网络这块弄明白还真不是件简单的事。

程序写的比较繁琐,代码也不合理,有时间再把程序优化一下,加上断点继传的功能。。

服务器端:

/******** http://blog.csdn.net/robertkun ********/
/*******  服务器程序  (server.c)     ************/

// linux 下读取大于2GB文件时,需指定
#define _FILE_OFFSET_BITS 64

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

// 定义包的大小为512KB
#define PACK_SIZE 1024*512

int main(int argc, char *argv[])
{
	// 设置输出缓冲
	setvbuf(stdout, NULL, _IONBF, 0);
	fflush(stdout);

	int sockfd,new_fd;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int sin_size,portnumber;
	char hello[]="Hello! Are You Fine?\n";

	if((portnumber=atoi("8080"))<0)
	{
		fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
		exit(1);
	}

	/* 服务器端开始建立socket描述符 */
	if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) {
		fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
		exit(1);
	}

	/* 服务器端填充 sockaddr结构  */
	bzero(&server_addr,sizeof(struct sockaddr_in));
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	server_addr.sin_port=htons(portnumber);

	/* 捆绑sockfd描述符  */
	if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) {
		fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
		exit(1);
	}

	/* 监听sockfd描述符  */
	if(listen(sockfd,5)==-1) {
		fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
		exit(1);
	}

	while(1)
	{
		fprintf(stderr, "server is listening!\n");

		/* 服务器阻塞,直到客户程序建立连接  */
		sin_size=sizeof(struct sockaddr_in);
		if( ( new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),(socklen_t*)&sin_size ) ) == -1) {
			fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
			exit(1);
		}

		fprintf(stderr,"Server get connection from %s\n",
			inet_ntoa(client_addr.sin_addr));
		if(write(new_fd,hello,strlen(hello))==-1) {
			fprintf(stderr,"Write Error:%s\n",strerror(errno));
			exit(1);
		}

		long int read_size = 0;
		unsigned long file_len  = 0;
		int order_id  = 0;
		char file_name[128] = {'\0'};
		char file_info[1024] = {'\0'};

		// 读取指令
		printf("\n\nWaiting for read file info!\n");
		int nn = 0;
		if(nn = read(new_fd, file_info, 1024)) 
		{
			// 指令ID
			int id_h = (int)file_info[0]<<8;
			order_id = id_h + (int)file_info[1];

			// 文件长度
			// 高16位
			unsigned long len_hig_1 = 0;
			memcpy(&len_hig_1, &file_info[2], sizeof(file_info[2]));

			unsigned long len_hig_2 = 0;
			memcpy(&len_hig_2, &file_info[3], sizeof(file_info[3]));

			unsigned long len_hig = len_hig_1 * 256 + len_hig_2;

			// 低16位
			unsigned long len_low_1 = 0;
			memcpy(&len_low_1, &file_info[4], sizeof(file_info[4]));

			unsigned long len_low_2 = 0;
			memcpy(&len_low_2, &file_info[5], sizeof(file_info[5]));

			int len_low = len_low_1 * 256 + len_low_2;
			file_len = len_hig * 256 * 256 + len_low;

			// 文件名称
			strncpy(file_name, &file_info[6], strlen(&file_info[6]));

			printf("order = %d, %lu, %s\n", order_id, file_len, file_name);

			if((strlen(file_name) == 0) || (file_len == 0))
			{
				printf("Read file info error!\n File_name or file_len is zero!\n");
				close(new_fd);
				continue;
			}
		}
		else {
			printf("Read file info error!\n");
			close(new_fd);
			close(sockfd);
			exit(0);
		}

		// 写入文件
		printf("\n\nWaiting for read file content!\n");
		FILE* pf = fopen(file_name, "wb+");
		if(pf == NULL)
		{
			printf("Open file error!\n");
			close(new_fd);
			continue;
		}

		char buff[PACK_SIZE] = {'\0'};
		while(read_size <= file_len) {
			//bzero(buff, 1024);
			int rlen = read(new_fd, buff, PACK_SIZE);
			if(rlen) {
				//system("clear");
				printf("\n\nRead package size = %d\n", rlen);

				int wn = fwrite(buff, sizeof(char), rlen, pf);
				read_size += rlen;

				printf("write file size = %d\n", wn);
				//printf("Read  total  size = %d\n", read_size);
			}
			else {
				printf("Read over!...%d\n", rlen);
				break;
			}
		} // End While

		printf("File len = %ld ... Already read size = %ld\n", file_len, read_size);
	
		/* 这个通讯已经结束     */
		fclose(pf);
		close(new_fd);
		/* 循环下一个     */
	}

	close(sockfd);
	exit(0);
}


客户端:

/******** http://blog.csdn.net/robertkun ********/
/******* 客户端程序  client.c        ************/

// linux 下读取大于2GB文件时,需指定
#define _FILE_OFFSET_BITS 64

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>	// 文件读写

// 定义包的大小为512KB
#define PACK_SIZE 1024*512

char* get_file_name(char* fn);
unsigned long get_file_size(const char *path);

int main(int argc, char *argv[])
{
	if(argc < 2)
	{
		printf("please input:<ip> <port> <filePath>.\n");
		return 0;
	}

        // 设置输出缓冲
        setvbuf(stdout, NULL, _IONBF, 0);
        fflush(stdout);

	char* filePath = argv[3];
	if(access(filePath, F_OK) != 0)
	{
		printf("file not existed!\n");
		return 0;
	}

        int sockfd;
        char buff[1024] = {'\0'};
        struct sockaddr_in server_addr;
        struct hostent *host;
        int portnumber,nbytes;

	const char* ip = argv[1];
        if((host=gethostbyname(ip))==NULL)
        {
                fprintf(stderr,"Gethostname error\n");
                exit(1);
        }

	const char* port = argv[2];
        if((portnumber=atoi(port))<0)
        {
                fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]);
                exit(1);
        }

        /* 客户程序开始建立 sockfd描述符  */
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
        {
                fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
                exit(1);
        }

        /* 客户程序填充服务端的资料       */
        bzero(&server_addr,sizeof(server_addr));
        server_addr.sin_family=AF_INET;
        server_addr.sin_port=htons(portnumber);
        server_addr.sin_addr=*((struct in_addr *)host->h_addr);

        /* 客户程序发起连接请求         */
        if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
        {
                fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
                exit(1);
        }

        /* 连接成功了           */
        if((nbytes=read(sockfd,buff,1024))==-1)
        {
                fprintf(stderr,"Read Error:%s\n",strerror(errno));
                exit(1);
        }
        buff[nbytes]='\0';
        printf("I have received:%s\n",buff);

	/******* 发送指令 ********/
	bzero(buff,1024);
	// 指令ID
	int order = 0x0010;
	int order_h = order >> 8;
	buff[0] = (char)order_h;
	buff[1] = (char)order;

	// 文件长度
	unsigned long len = get_file_size(filePath);
	printf("file size = %lu\n", len);

	// 高16位
	int len_h = len >> 16;
	int len_h_1 = len_h >> 8;
	buff[2] = (char)len_h_1;
	buff[3] = (char)len_h;

	// 低16位
	int len_l = len;
	int len_l_1 = len_l >> 8;
	buff[4] = (char)len_l_1;
	buff[5] = (char)len_l;

	// 文件名称
	char* fileName = get_file_name(filePath);
	printf("file name = %s\n", fileName);
	strncpy(&buff[6], fileName, strlen(fileName));

	write(sockfd,buff,1024); 	
	
	/******* 发送文件 ********/
	printf("file path = %s\n", filePath);
	FILE* pf = fopen(filePath, "rb");
	if(pf == NULL) {
		printf("open file failed!\n");
		exit(0);
	}

	char pack[PACK_SIZE] = {'\0'};
	while((len = fread(pack, sizeof(char), PACK_SIZE, pf)) > 0)
    	{
		system("clear");
		printf("send data size = %d \t", len);
		write(sockfd, pack, len);
		bzero(pack,PACK_SIZE);
		//sleep(1);
    	}
	
        /* 结束通讯     */
        close(sockfd);
        exit(0);
}

char* get_file_name(char* fn)
{
	int last = 0;
	char* pfn = fn+strlen(fn)-1;
	int i=0;
	for(i=0; i<strlen(fn); ++i)
	{
		if(*pfn-- == '/')
		{
			last = strlen(fn)-i;
			break;
		}
	}

	char* name = (char*)malloc(sizeof(char)*256);
	char* pname = name;
	int j=0;
	for(j=last; j<strlen(fn); ++j, ++pname)
	{
		*pname = fn[j];
	}
	
	return name;
}

unsigned long get_file_size(const char *path)
{
	unsigned int filesize = 0;
	struct stat statbuff;
	if(stat(path, &statbuff) < 0) {
		printf("Get file stat failed!\n");
		return filesize;
	}else{
		filesize = statbuff.st_size;
	}

	return filesize;
}

MAKEFILE:

服务器端:

object=server.o

server.o:
        gcc -g -c server.c
        gcc -o server $(object)

clean:
        rm server $(object)

客户端:

object=client.o

client.o:
        gcc -g -c client.c
        gcc -o client $(object)

clean:
        rm -rf client $(object)


你可能感兴趣的:(linuxC socket 发送和接收文件小例子)