实现代码
tcp.h
#ifndef _TCP_H_
#define _TCP_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <fcntl.h>
#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<addr><post>\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<filename>\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
通过以上代码就可以实现用文件名称来传输文件了