TLV資料傳輸例項
阿新 • • 發佈:2019-02-12
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; }