代码语言:javascript复制
/********************************************************************************************
功能: http服务器端测试程序
时间:2014-03-19
说明:网络服务器端程序一般是守护进程,这里只是测试调试,
没有做到守护。因此只支持单用户单次服务。
http服务器逻辑:
1.创建一个socket,bind一个socket,listen
2.客户端发来connect,服务器进行accept
3.客户端发来 ( send )请求get ,post 等,服务器读取请求
3.服务器端对请求进行分析:提取url;通过url搜索请求资源,如果
请求资源成功,则发出请求成功的响应
4.发出http响应(response)
5.客户端获得响应成功,就等待服务器发出数据并接收数据
*********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sched.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/syscall.h>
#define DEFAULT_CONTENT_DIR "/home/hfl/hflsamb/network"
#define ALIGN_4096 (4096 - 1)
#define BUF_SIZE (188*7*128)
#define NUM_BUF_DESC 24
#define O_DIRECT 0x8000
#define FILENAME_MAX_LEN 256
char url[256]; /* content name to stream out */
char url_root[256]; /* Root directory where content is */
char recvbuf[1024];
char sendbuf[2048];
char response[2048];
off_t filesize;
void usage()
{
printf("Usage: http_test_server [-p <port> -a -r <rate> -c <cpu affinity> -m -f <content-directory> -l -k -h]n");
printf("options are:n");
printf(" -p <port> # port to listen on (default: 5000)n");
printf(" -r <rate> # rate (default: 20Mpbs)n");
printf(" -c <cpu affinity> # affinity (1 || 2 || 3, default: CPU0 = 1; CPU1 = 2; ANY = 3)n");
printf(" -m # send test pattern from memory (default: stream file from disk)n");
printf(" -f <content-directory # (default: /data/videos) n");
printf(" -l # keep resending the file (default: stream only once)n");
printf(" -v # print periodic stats (default: no)n");
printf(" -k # disable TCP checksum computation (default: enabled)n");
printf(" -h # prints http_test_server usagen");
printf("n");
}
double difftime1(struct timeval *start, struct timeval *stop)
{
double dt = 1000000.*(stop->tv_sec - start->tv_sec) (stop->tv_usec - start->tv_usec);
return dt;
}
/* Open the listener service on port 5000 */
int tcpServerSetup(int port, int socket_type)
{
struct sockaddr_in localAddr;
int sd;
int reuse_flag = 1;
if ( (sd = socket(AF_INET, socket_type, 0)) < 0) {
/* Socket Create Error */
perror("Socket Open Err");
return -EINVAL;
}
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = htons(port);
if(setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_flag, sizeof(reuse_flag) ) < 0 ) {
printf("REUSE Socket Errorn");
return -EINVAL;
}
if (bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr))) {
perror("Socket Bind Err");
return -EINVAL;
}
if (listen(sd, 4)) {
perror("Socket listen Err");
return -EINVAL;
}
return sd;
}
/* Parses the input for pattern begin; followed by pattern end */
int parseToken(char *input, char *output, int output_len, char *begin, char *end)
{
char *p_begin = strstr(input, begin);
char *p_end;
char temp;
if (p_begin)
{
p_begin = strlen(begin);
p_end = strstr(p_begin,end);
if(!p_end)
return -1;
temp = *p_end;
*p_end = 0;
printf("TokenFound = [%s]n",p_begin);
strncpy(output,p_begin, output_len-1);
*p_end = temp;
return 0;
}
return -1; /* Not found */
}
int openUrlFile(char *url, char *filename)
{
struct stat file_stat;
char *p;
FILE *fp;
filename[0] = 0;
snprintf(filename, FILENAME_MAX_LEN, "%s/%s", url_root, url);
while(stat(filename, &file_stat)) {
if ( (p = strstr(filename,".mp3"))) {
printf("Original %s, ",filename);
strncpy(p,".mp3", FILENAME_MAX_LEN-6);
printf("Trying [%s] ",filename);
if(stat(filename, &file_stat)) {
printf("Failedn");
return -1;
}
printf("OKn");
break;
}
return 0;
}
/* File found */
filesize = file_stat.st_size;
return 0;
}
#ifdef USE_POLL
#include <sys/poll.h>
void waitForNetworkEvent(int sd)
{
struct pollfd pfd;
int rc;
pfd.fd = sd;
pfd.events = POLLIN | POLLPRI;
pfd.revents = 0;
while (1) {
if ( (rc = poll(&pfd, 1, -1)) < 0) {
perror("ERROR: select(): exiting...");
exit(1);
}
else if (rc == 0)
continue;
else if (pfd.revents == POLLIN)
break;
}
return;
}
#else /* Use select */
void waitForNetworkEvent(int sd)
{
fd_set rfds;
struct timeval tv;
while (1) {
FD_ZERO(&rfds);
FD_SET(sd, &rfds);
tv.tv_sec = 2;
tv.tv_usec = 0;
if ( select(sd 1, &rfds, NULL, NULL, &tv) < 0 ) {
perror("ERROR: select(): exiting...");
break;
}
if (!FD_ISSET(sd, &rfds))
/* No request from Client yet, go back to select loop */
continue;
break;
}
return;
}
#endif
/* waits for incoming HTTP requests, sends out HTTP response and returns new socket descriptor */
int handleHttpRequest(int sd, int socket_type, char *filename)
{
fd_set rfds;
struct timeval tv;
int nsd = -1;
struct sockaddr_in remoteAddr;
int addrLen = sizeof(remoteAddr);
int nbytes;
while (1) {
waitForNetworkEvent(sd);
/* accept connection */
if ( (nsd = accept(sd, (struct sockaddr *)&remoteAddr, (socklen_t *)&addrLen)) < 0 ) {
perror("ERROR: accept(): exiting...");
break;
}
printf("Accepted Connection from %lx:%d n", remoteAddr.sin_addr.s_addr, ntohs(remoteAddr.sin_port));
waitForNetworkEvent(nsd);
/* Read HTTP request */
if ((nbytes = read(nsd, recvbuf, 1024)) <= 0) {
perror("read failed to read the HTTP Get requestn");
continue;
}
recvbuf[nbytes] = 0;
printf("Read HTTP Req ( %d bytes)[n%s]n", nbytes, recvbuf);
/* Parse HTTP request & open the content file */
parseToken(recvbuf, url, sizeof(url), "GET /", " ");
if( openUrlFile(url, filename) ) {
printf("File Not found, go back to listeningn");
continue;
}
printf("Stream file = %s size=%lldn", filename, filesize);
/* Build HTTP response */
strncpy(response,
"HTTP/1.1 200 OKrn"
"Content-Length: %lldrn"
/*"Content-Type: video/mpegrn"*/
"Connection: Keep-Alivern"
"Accept-Ranges: bytesrn"
"Connection: closern"
"Content-Range: bytes 0-%lld/%lldrn"
"Server: Linux/2.6.18, UPnP/1.0, my test apprn"
"rn",
sizeof(response)-1);
nbytes = snprintf(sendbuf, sizeof(sendbuf), response, filesize, filesize-1, filesize);
printf("HTTP Response [n%s]", sendbuf);
/* send out HTTP response */
if (write(nsd, sendbuf, nbytes) != nbytes) {
printf("Failed to write HTTP Response of %d bytesn", nbytes);
perror("write(): n");
break;
}
return nsd;
}
return -1;
}
int main(int argc, char *argv[])
{
int port = 5000; /* Server Port */
unsigned long cpu_affinity_mask = 1; /* CPU0 = 1, CPU1 = 2; CPU0 || CPU1 = 3 */
unsigned long new_mask;
double rate = 19.4; /* Default rate to stream content at */
int loop = 0;
int send_from_memory = 0;
struct timeval start, stop;
int verbose = 0;
int disable_checksum = 0;
int sd; /* socket descriptor */
unsigned long count = 0;
unsigned long total = 0;
int buflen = BUF_SIZE;
struct sockaddr_in dest;
int c, i, j;
int fd = -1;
unsigned char *xbuf, *buf;
int len;
loff_t bytes= 0;
double dt=0, maxrate = 19.4;
struct iovec iov[NUM_BUF_DESC];
int nextBuf;
int socket_type;
char filename[FILENAME_MAX_LEN];
url[0] = '