我正在尝试使用c和bash为网络服务器目的制作netcat的副本.这是我在bash中的代码:
#!/bin/bash
rm -f out
mkfifo out
trap "rm -f out" EXIT
cat out | nc -l 1500 > >(
while read line
do
echo $line
# parse http request from line
# some other things that doesnt matter
printf "HTTP/1.1 200 OK\nContent-Type:text/html\n\ntest" > out
done
)
当我访问localhost:1500时,它打印“test”.我想用自己的netcat替换netcat(nc).
cat out | customnc -l 1500 > >(
#
)
这是customnc.c
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
int create_socket, new_socket;
socklen_t addrlen;
int bufsize = 1024;
char *buffer = malloc(bufsize);
struct sockaddr_in address;
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){
printf("The socket was created\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(1600);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0){
printf("Binding Socket\n");
}
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) {
perror("server: accept");
exit(1);
}
if (new_socket > 0){
printf("The Client is connected...\n");
}
recv(new_socket, buffer, bufsize, 0);
printf("%s", buffer);
close(new_socket);
close(create_socket);
return 0;
}
我的代码出了什么问题?当我点击localhost:1600(customnc)时,它只会抛出错误无法连接.
问题是从bash发送数据.如果我使用write在customnc.c中发送响应,浏览器将显示该消息,但我必须从bash发送它.
编辑:真正的问题是我想在bash中解析http请求并使用bash将文件发送到c.所以它是这样的:
1. Bash启动c服务器
2.用户在浏览器中打开localhost
3. C将收到请求并将其发回bash
4. Bash将解析请求并将响应(文本)发送给c
5. C将收到响应并通过套接字发送到浏览器
6. C将关闭套接字
我正在尝试实现这一点,但我无法进行这种双向通信.我可以使用命名管道(2)吗?
最佳答案 您在写入任何内容之前关闭套接字.您需要从stdin读取数据并在关闭之前将其写入套接字.尝试在调用close(new_socket)之前添加它:
char c;
while ((c = getchar()) != EOF) {
write(new_socket, &c, 1);
}
这是我的完整代码,我还添加了更多错误检查,添加了对fflush(stdout)的调用,删除了printf调用,以便它们不会被bash脚本解析,删除对malloc的不必要调用,并在上面设置SO_REUSEADDR套接字因此可以快速重复使用(见this answer for more info).
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define BUFSIZE 1024
int main()
{
int create_socket, new_socket;
socklen_t addrlen;
char buffer[BUFSIZE];
struct sockaddr_in address;
char c;
int true = 1;
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("server: socket");
exit(1);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(1600);
setsockopt(create_socket,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int));
if (bind(create_socket, (struct sockaddr *)&address, sizeof(address)) < 0)
{
perror("server: bind");
exit(1);
}
if (listen(create_socket, 10) < 0)
{
perror("server: listen");
exit(1);
}
if ((new_socket = accept(create_socket, (struct sockaddr *)&address, &addrlen)) < 0)
{
perror("server: accept");
exit(1);
}
if (recv(new_socket, buffer, BUFSIZE, 0) < 0)
{
perror("server: recv");
exit(1);
}
printf("%s", buffer);
fflush(stdout);
while ((c = getchar()) != EOF)
{
if (write(new_socket, &c, 1) < 0)
{
perror("server: write");
exit(1);
}
}
close(new_socket);
close(create_socket);
return 0;
}
这适用于以下bash脚本.请注意,我添加了一个空行检查,表示GET请求的结束.
#!/bin/bash
rm -f out
mkfifo out
trap "rm -f out" EXIT
cat out | ./a.out > >(
while read line
do
# strip carriage return
line=$(echo $line | tr -d '\r')
echo $line
if [[ $line == "" ]]; then
# reached end of GET request
break
fi
done
printf "HTTP/1.1 200 OK\nContent-Type:text/html\n\ntest" > out
)
如果要完全替换nc命令,则必须进行一些参数解析以获取端口号(-l),而不是将其硬编码为1600.