对许多函数还不是很熟悉
这里面使用了iovec,可以避免了将几个字符串再拼接起来,减少开销。
主要思路如下:
1.读取文件
2.设置头文件
3.发送
服务器代码:
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/uio.h>
#include<fcntl.h>
#define BUFFER_SIZE 1024
static const char* line_stat[2] = {"200 OK", "500 Internal server error"};
int main(int argc, char* argv[]){
if(argc <= 3){
printf("ip and port \n");
return 0;
}
char* ip = argv[1];
int port = atoi(argv[2]);
char* file_name = argv[3];
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
inet_pton(AF_INET, ip, &addr.sin_addr);
int ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
assert(ret != -1);
ret = listen(sockfd, 5);
assert(ret != -1);
struct sockaddr_in clientaddr;
socklen_t clientaddr_len;
int connfd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);
if(connfd < 0){
printf("errno is : %s \n", errno);
}else{
char header_buf[BUFFER_SIZE];
memset(header_buf, '\0', sizeof(header_buf));
struct stat file_stat;
char* file_buffer;
bool valid = true;
if(stat(file_name, &file_stat) < 0){//文件不存在
valid = false;
}else{
if(S_ISDIR(file_stat.st_mode)){ //文件是目录
valid = false;
}else if(file_stat.st_mode & S_IROTH){ //文件可读
int fd = open(file_name, O_RDONLY);
file_buffer = new char[file_stat.st_size + 1];
memset(file_buffer, '\0', sizeof(file_buffer));
if(read(fd, file_buffer, file_stat.st_size) < 0){ //读取有问题
valid = false;
}
}else{
valid = false;
}
}
int len = 0;
if(valid){ //如果文件有效
ret = snprintf(header_buf, BUFFER_SIZE - 1, "%s %s\r\n", "HTTP:/1.1", line_stat[0]);
len += ret;
ret = snprintf(header_buf + len, BUFFER_SIZE - 1 - len, "content length : %d\r\n", file_stat.st_size);
len += ret;
ret = snprintf(header_buf + len, BUFFER_SIZE - 1 - len, "%s", "\r\n");
struct iovec iov[2];
iov[0].iov_base = header_buf;
iov[0].iov_len = strlen(header_buf);
iov[1].iov_base = file_buffer;
iov[1].iov_len = file_stat.st_size;
writev(connfd, iov, 2);
}else{
ret = snprintf(header_buf, BUFFER_SIZE - 1, "%s %s\r\n", "HTTP:/1.1", line_stat[1]);
len += ret;
ret = snprintf(header_buf + len, BUFFER_SIZE - 1 - len, "%s", "\r\n");
send(connfd, header_buf, strlen(header_buf), 0);
}
close(connfd);
delete[] file_buffer;
}
close(sockfd);
return 0;
}
客户端代码:
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#define BUFFER_SIZE 1024
int main(int argc, char* argv[]){
if(argc <= 2){
printf("ip and port and size!!!\n");
return 0;
}
char* ip = argv[1];
int port = atoi(argv[2]);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serveraddr;
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(port);
inet_pton(AF_INET, ip, &serveraddr.sin_addr);
if((connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr))) < 0){
printf("connect failure \n");
}else{
char buf[BUFFER_SIZE];
memset(buf, '\0', BUFFER_SIZE);
int ret;
while((ret = recv(sockfd, buf, sizeof(buf), 0)) > 0){
printf("%s", buf);
}
}
close(sockfd);
return 0;
}
运行结果:
服务器
客户端
a.txt