现在的位置: 首页 > 综合 > 正文

TCP文件传输

2019年08月11日 ⁄ 综合 ⁄ 共 3343字 ⁄ 字号 评论关闭

下面是一个简单的TCP文件传输的例子,实现环境:Linux C

Server.c

// 向客户端发送文件

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

#define MAXBUFF 1024

// 通过sock来发送指定的文件
int sendFile(char *srcFile, int sock)
{
	int inFile;
	if((inFile = open(srcFile, O_RDONLY)) == -1) //只读方式打开test.txt ,iffile文件指针
	{
		printf("找不到文件[%s]或打不开, 停止运行\n", srcFile);
		return -1;								// 发送文件失败
	}

	int nread;
	char buf[MAXBUFF] = {0};

	while((nread = read(inFile, buf, MAXBUFF)) > 0)
	{
		if(write(sock, buf, nread) == -1)		// 将缓冲区的内容写到sock
			printf("写sock出了错\n");
	}
	close(inFile);

	return 0;									// 发送文件成功
}

int main()
{
	int sock,length,clilen;
	struct sockaddr_in server, client;

	/******************************建立Socket连接*********************************/
	sock = socket(AF_INET,SOCK_STREAM,0); //申请socket资源
	if (sock < 0)
	{
		perror("socket");
		return 1;
	}

	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;	// 必然的,这里指的是Internet协议*/
	server.sin_port = 0;					// 这里,是让系统自动分配一个端口号,在1024到5000之间65535个端口 ,端口设为0,系统自动分配  
	if (bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) // 将IP地址和端口号绑到sock上
	{
		perror("bind");
		return 1;
	}

	length = sizeof(server);
	if (getsockname(sock, (struct sockaddr *)&server, &length) < 0) /*获得指定socket的本地地址,成功返回0,错误返回-1*/
	{
		perror("getsockname");
		return 1;
	}
	printf("Socket port #%d\n", ntohs(server.sin_port)); /* 打印出系统分的端口号,给client用*/
	listen(sock, 5);									/*5个连接请求排队等待,一般5个 Pause Here 等待client连接*/

	/****************现在是等待客户来连接,如果来客户了,那就建好了socket,就可以当文件使用**********/
	clilen = sizeof(client);   
	int msgsock = accept(sock,(struct sockaddr *)&client,(int *) &clilen);	/*创建一个新的与sock相同的socket并返回其值*/
	if (msgsock == -1)
		perror("accept");
	else
	{
		char srcFile[] = "test.txt";
		if(sendFile(srcFile, msgsock) == 0)
			printf("发送文件[%s]成功\n", srcFile);
		else
			printf("发送文件[%s]失败\n", srcFile);
	} 
	close(msgsock);									// 关闭临时套接字
	close(sock);

	return 0;
}

Client.c

// 功能:接收服务器发送过来的数据,保存到本地文件

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

#define MAXBUFF 1024
#define PERM 0644			// 创建文件的默认属性

// 通过sock接收数据保存到文件destFile
int recvFile(char *destFile, int sock)
{
	int outFile, nread;
	char buf[MAXBUFF] = {0};

	if((outFile = open(destFile, O_WRONLY|O_CREAT|O_TRUNC, PERM)) == -1) //创建文件
		return 1;

	while((nread = read(sock, buf, MAXBUFF)) > 0) /*从sock读取传来的文件内容到缓冲区*/
	{ 
		if(write(outFile, buf, nread) == -1)		/*将缓冲区的内容写到文件里*/
		{
			printf("写文件时出错, 中止接收文件\n");
			close(outFile);
			return 1;
		}
	}
	close(outFile);

	return 0;
}

int main(int argc, char *argv[])
{
	int sock;
	struct sockaddr_in server;
	struct hostent *hp;

	if(argc < 3)
	{
		printf("Usage: %s <hostname> <server port>\n", argv[0]);
		return 1;
	}

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	{
		perror("socket");
		return 1;
	}

	server.sin_family = AF_INET;
	hp = gethostbyname(argv[1]); /*根据主机名查地址,返回指针指向hostent结构*/
	if (hp == 0)
	{
		fprintf(stderr, "%s: unknown host\n", argv[1]);
		return 1;
	}
	memcpy((char *)&server.sin_addr,(char *)hp->h_addr, hp->h_length);	// 拷贝Internet地址
	server.sin_port = htons(atoi(argv[2]));								// argv[2]是服务器端口号
	if (connect(sock,(struct sockaddr *)&server,sizeof(server)) < 0)	// 根据server地址连接sock,建立一条真实的连接
	{
		perror("connect");
		close(sock);
		return 1;
	}

	char destFile[] = "test_out.txt";
	if(recvFile(destFile, sock) == 0)
	{
		printf("接收文件[%s]成功\n\n", destFile);
	}
	else
	{
		printf("创建输出文件[%s]出错, 请检查\n", destFile);
	}
	close(sock);

	return 0;
}

如果要检查文件传输过程有没有出错,可以通过命令:wc或计算MD5值来作比较。

我的检测结果:

[zcm@t #64]$cat test.txt |wc
     89     183    2901
[zcm@t #65]$cat test_out.txt |wc
     89     183    2901
[zcm@t #66]$md5sum test.txt test_out.txt 
fffb6bcab6154aad9f7dfe4f5d945bc3  test.txt
fffb6bcab6154aad9f7dfe4f5d945bc3  test_out.txt

 

抱歉!评论已关闭.