TCP文件传输功能

实现代码

tcp.h

#ifndef _TCP_H_
#define _TCP_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define ErrExit(msg) do { perror(msg); exit(0);} while(0) 
#define BACKLOG 5
#define OK '1'

typedef struct sockaddr_in Addr_in;
typedef struct sockaddr Addr;

typedef ssize_t (* DataHand_t)(int, void *, size_t, int);


void Argment(int argc, char *argv[]);
int SocketInit(char *argv[], bool flag);
int SocketDataHand(int fd, void *buf, size_t len, DataHand_t datahandle);
#endif

tcp.c

#include "tcp.h"
void Argment(int argc, char *argv[]) {
	if(argc < 2) {
		fprintf(stderr, "%s\n", argv[0]);
		exit(EXIT_FAILURE);
	}
}

int SocketInit(char *argv[], bool flag) {
	int fd;
	Addr_in addr;

	/*创建套接字*/
	if ( (fd = socket(AF_INET, SOCK_STREAM, 0) ) < 0){
		ErrExit("socket");
	}
	/*设置通信结构体*/
	bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port  = htons( atoi(argv[2]) );
	if (inet_aton(argv[1], &addr.sin_addr) == 0) {
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}

	if (flag == true) {
		/*发起连接请求*/
		if (connect(fd, (Addr *)&addr, sizeof(addr)) ) {
			perror("connect");
			exit(0);
		}
	} else {
		/*发起连接请求*/
		if (bind(fd, (Addr *)&addr, sizeof(addr)) ) {
			perror("connect");
			exit(0);
		}

		/*允许地址快速重用*/
		int b_reuse = 1;
		if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(b_reuse) ) )
			perror("setsockopttsockopt");

		/*监听模式*/
		if ( listen(fd, BACKLOG))
			ErrExit("listen");
	}
	

	return fd;
} 

int SocketDataHand(int fd, void *buf, size_t len, DataHand_t datahandle) {
	int ret;
	char *str = datahandle == recv ? "recv" : "send";

	do {
		ret = datahandle(fd, buf, len, 0);
	} while (ret < 0 && errno == EINTR);
	if (ret < 0) 
		ErrExit(str);

	return ret;
}

server.c

#include "tcp.h"

int main (int argc, char *argv[]) {
	int fd, newfd;
	int ret, file_fd;
	char buf[BUFSIZ] = {};
	Addr_in addr, client_addr;
	socklen_t addrlen = sizeof(addr);

	/*检查参数*/
	Argment(argc, argv);

	/*创建套接字*/
	fd = SocketInit(argv, false);
	/*接收客户端连接*/
	do {
		newfd = accept(fd, (Addr *)&client_addr, &addrlen);
	} while( newfd < 0 && errno == EINTR) ;//如果信号导致的错误,继续执行

	/*接收文件名字*/
	ret = SocketDataHand(newfd, buf, BUFSIZ, (DataHand_t)recv);
	
	/*创建文件*/
	if ( (file_fd = open(buf, O_WRONLY|O_CREAT, 0660)) < 0) {
		ErrExit("file_fd");
	}
	buf[0] = OK;
	SocketDataHand(newfd, buf, 1, (DataHand_t)send);

	/*接受文件*/
	while (1) {
		ret = SocketDataHand(newfd, buf, BUFSIZ, (DataHand_t)recv);
		if (!ret) {
			break;
		}
		write(file_fd, buf, ret);
	}

	close(newfd);
	close(fd);
	return 0;
}

client.c

#include "tcp.h"

#define FILENAME "picture.png"
#define INFOFILE ".info"
int main (int argc, char *argv[]) {
	int fd;
	int ret, file_fd;
	char buf[BUFSIZ];
	FILE *fp;
	char *filename = argv[1];
	/*检查参数*/
	if(argc < 2) {
		printf("%s\n", argv[0]);
		exit(0);
	}

	/*通过配置文件获取IP地址和端口号*/
	if ( (fp = fopen(INFOFILE, "r"))  < 0) 
		ErrExit("fopen");
	
	fgets(buf, 20, fp);
	buf[strlen(buf)-1] = '\0';
	argv[1] = buf;
	fgets(&buf[20], 20, fp);
	buf[strlen(&buf[20])-1 + 20] = '\0';
	argv[2] = &buf[20];

	/*创建套接字*/
	fd = SocketInit(argv, true);

	/*打开文件*/
	if ( (file_fd = open(filename, O_RDONLY)) < 0 ) {
		ErrExit("open");
	}
	/*发送文件名*/
	SocketDataHand(fd, filename, strlen(filename), (DataHand_t) send);
	SocketDataHand(fd, buf, 1, recv);

	/*发送文件*/
	if (buf[0] == OK) {
		while (1) {
			do {
				ret = read(file_fd, buf, BUFSIZ);
			} while (ret < 0 && errno == EINTR);
			if(ret < 0) 
				ErrExit("read");
			if(!ret)
				break;
			ret = SocketDataHand(fd, buf, ret, (DataHand_t) send);
			if(!ret)
				break;
		}
	}
	printf("flie success\n");
	close(file_fd);
	close(fd);
	return 0;
}

.info

127.0.0.1
8888

通过以上代码就可以实现用文件名称来传输文件了
TCP文件传输功能_第1张图片

你可能感兴趣的:(tcp/ip,网络协议,网络)