1. 程式人生 > >TLV資料傳輸例項

TLV資料傳輸例項

TLV標頭檔案

#ifndef __TLV_H__
#define __TLV_H__

//傳送命令的型別(獲取檔案列表還是指定檔案)
enum type_t{
	FLIST = 0,
	FGET
};

enum send_status_t{
	SEND_FHEAD = 1,
	SEND_FBODY,
	SEND_FOVER
};

//傳送資料的命令頭結構
typedef struct{
	unsigned char type;
	unsigned long len;
}cmd_head_t;

//傳送的檔案頭部資訊
typedef struct{
	char fname[256];
	unsigned long flen;
}file_head_t;

enum is_start_t{
	START = 0,
	STOP
};

typedef struct 
{
	int sock_fd;
	int file_fd;
	int is_start;
	int send_status;
}client_info_t;


#endif

伺服器示例

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

#define MAX_SIZE 512


int send_data(int sockfd, char *data, int len)
{
	int recv_len = 0;
	int total_len = 0;
	while (total_len < len){
		recv_len = send(sockfd, data + total_len, len - total_len, 0);
		if (recv_len < 0){
			if (errno == EAGAIN || errno == EINTR){
				usleep(1000);
				continue;
			}
			return -1;
		}
		total_len += recv_len;
	}
	return 0;
}

int recv_data(int sockfd, char *data, int len)
{
	int count = 0;
	int recv_len = 0;
	while (recv_len < len){
		recv_len = recv(sockfd, data, len, 0);
		if (errno == EAGAIN || errno == EINTR){
			if (count++ > 5){
				printf("count error\n");
				return -1;
			}
			usleep(1000);
			continue;
		}
	}
	return recv_len;
}

int main(int argc, char *argv[])
{
	int sockfd;
	int ret;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int client_sockfd;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0){
		perror("socket error");
		return -1;
	}

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(9000);
	server_addr.sin_addr.s_addr = inet_addr("192.168.121.128");

	int opt = 1;
	if(setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, (const void *)&opt, sizeof(opt))){
		perror("setsockopt");
		return -1;
	}
	int len = sizeof(struct sockaddr_in);
	ret = bind(sockfd, (struct sockaddr*)&server_addr, len);
	if (ret == -1){
		perror("bind error");
		return -1;
	}
	ret = listen(sockfd, MAX_SIZE);
	if (ret < 0){
		return -1;
	}
	char buff[MAX_SIZE] = {0};
	char filename[256] ={0};
	file_head_t fh;
	int flag;
	int opret = -1;
	while (1){
		client_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &len);
		if (client_sockfd < 0){
			continue;
		}
		printf("new client--ip:[%s], port:[%d]\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
		while (1){
			memset(buff, 0x00,MAX_SIZE);
			memset(filename, 0x00,256);
			memset(&fh, 0x00, sizeof(file_head_t));
			int recv_len = recv_data(client_sockfd, (char*)&flag, sizeof(int));
			if (((int)flag) == SEND_FHEAD){
				recv_len = recv_data(client_sockfd, (char *)&fh, sizeof(file_head_t));
				printf("file name:[%s], size:[%ld]\n", fh.fname, fh.flen);
				sprintf(filename, "../%s", fh.fname);
				opret = open(filename , O_CREAT | O_RDWR | O_TRUNC | O_APPEND, 0666);
				if (opret < -1){
					perror("open error");
					return -1;
				}
			}else if (((int)flag) == SEND_FBODY){
				recv_len = recv_data(client_sockfd, buff, MAX_SIZE);
			}else if (((int)flag) == SEND_FOVER){
				break;
			}
			//printf("recv_len = %d\n", recv_len);
			if (recv_len == MAX_SIZE){
				//printf("recv buff:%s\n", buff);
				write(opret, buff, strlen(buff));
			}
		}
		close(client_sockfd);
	}
	close(opret);
	close(sockfd);
	return 0;
}

客戶端示例

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

#define MAX_SIZE 512

int recv_data(int sockfd, char *data, int len)
{
	int recv_len = 0;
	int count = 0;
	while (recv_len < len){
		recv_len = recv(sockfd, data, len, 0);
		if (errno == EAGAIN || errno == EINTR){
			if (count++ > 5){
				return -1;
			}
			usleep(1000);
			continue;
		}
		if (recv_len != len){
			return -1;
		}
	}
	return 0;
}

int send_data(int sockfd, char *data, int len)
{
	int recv_len = 0;
	int total_len = 0; 
	while (total_len < len){
		recv_len = send(sockfd, data + total_len, len - total_len, 0);
		printf("send_data recv_len = %d\n", recv_len);
		if (recv_len < 0){
			if (errno == EAGAIN || errno == EINTR){
				usleep(1000);
				continue;
			}
			return -1;
		}
		total_len += recv_len;
	}
	return total_len;

}

int main(int argc, char *argv[])
{
	int sockfd;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int ret;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0){
		perror("socket error");
		return -1;
	}

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(9000);
	server_addr.sin_addr.s_addr = inet_addr("192.168.121.128");

	client_addr.sin_family = AF_INET;
	client_addr.sin_port = htons(8000);
	client_addr.sin_addr.s_addr = inet_addr("192.168.121.128");

	int opt = 1;
	if(setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, (const void *)&opt, sizeof(opt))){
		perror("setsockopt");
		return -1;
	}
	int len = sizeof(struct sockaddr_in);
	ret = bind(sockfd, (struct sockaddr*)&client_addr, len);
	if (ret == -1){
		perror("bind error");
		return -1;
	}

	ret = connect(sockfd, (struct sockaddr*)&server_addr, len);
	if (ret < 0){
		perror("connect error");
		return -1;
	}
	int opret;
	//開啟要傳送的檔案
	if ((opret = open("./hehe.txt", O_RDONLY)) < 0){
		perror("open error");
		return -1;
	}
	//設定客戶端資訊
	client_info_t *pci;
	pci = (client_info_t *)malloc(sizeof(client_info_t));
	pci->sock_fd = sockfd;
	pci->file_fd = opret;
	pci->send_status = SEND_FHEAD; //傳送檔案頭資訊

	file_head_t fh;
	memset(&fh, 0x00, sizeof(file_head_t));
	memcpy(fh.fname, "hehe.txt", strlen("hehe.txt"));
	fh.flen = strlen("hehe.txt");
	int send_len = MAX_SIZE;
	char buff[MAX_SIZE] = {0};
	int i = 0, s_len;
	while (1){
		memset(buff, 0x00, MAX_SIZE);
		if (pci->send_status == SEND_FHEAD){
			printf("send file head\n");
			//告訴伺服器即將傳送檔案頭資訊
			send_data(pci->sock_fd, (char *)&pci->send_status, sizeof(pci->send_status));
			//開始傳送檔案頭資訊
			send_data(pci->sock_fd, (char *)&fh, sizeof(file_head_t));
			//修改傳送狀態為傳送檔案資料
			pci->send_status = SEND_FBODY;
		}else if (pci->send_status == SEND_FBODY){
			printf("send file data\n");
			//告訴伺服器即將傳送檔案資料
			send_data(pci->sock_fd, (char*)&pci->send_status, sizeof(pci->send_status));
			s_len = 0;
			while (s_len < send_len){
				int re_ret = read(pci->file_fd, buff, send_len - s_len);
				//printf("buff:[%s]\n", buff);
				send_data(pci->sock_fd,buff, MAX_SIZE);
				s_len += re_ret;
				sleep(1);
				if (re_ret == 0){
					close(pci->file_fd);
					pci->file_fd = -1;
					pci->send_status = SEND_FOVER;
					break;
				}
			}
		}else if (pci->send_status == SEND_FOVER){
			//告訴伺服器檔案內容傳送完畢
			send_data(pci->sock_fd, (char*)&pci->send_status, sizeof(pci->send_status));
			break;
		}
	}
	close(sockfd);

	return 0;
}