您好,登錄后才能下訂單哦!
網絡駭客入門之TCP并發網頁服務器
TCP并發服務器本來準備寫在網絡駭客入門之TCP編程后面的,但是因為代碼有點長,所以就單獨寫了一篇
注意:
因為瀏覽器發送的數據比較多,所以作為本服務器的接受緩沖區recv_buf要大點,至少512字節,建議1024字節
如果接收不全的話,無論如何都不能將網頁傳給瀏覽器,這個bug卡了我一晚上,所以記得特別清楚。
創建線程時傳給線程的參數注意寫連接套接字的值,先轉換為(void*)類型,
pthread_create(&pth,NULL,msg_echo,(void *)connfd);
再在線程里轉回(int)型
int connfd = (int)arg;
不能寫地址,防止如果同時有多個請求時connfd的值變得太快,在子線程取地址取出來之前值就變了
1.頭文件
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <fcntl.h>
//子線程處理瀏覽器的網頁請求
void *msg_echo(void *arg)
{
int connfd = (int)arg;
int ret_read=0;
int ret_recv=0;
char recv_buf[1024]="";
char read_buf[1024]="";
char send_buf[1024]="";
int fd;
char filename[50] = "html/";
//請求成功返回
char head[]="HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n" \
"\r\n";
//請求失敗返回
char err[]= "HTTP/1.1 404 Not Found\r\n" \
"Content-Type: text/html\r\n" \
"\r\n" \
"<HTML><BODY>File not found</BODY></HTML>";
printf("connfd=%d\n",connfd);
//接收請求數據
ret_recv = recv(connfd,recv_buf,sizeof(recv_buf),0);
printf("ret_recv:%d\n",ret_recv);
//讀取網頁文件名
sscanf(recv_buf+4, "%[^ ]", (filename + 5));
printf("filename:%s\n",filename);
//打開網頁文件
fd = open(filename, O_RDONLY);
if(fd < 0)
{
perror("open");
send(connfd, err, strlen(err), 0);
close(connfd);
return NULL;
}
//將網頁文件發給瀏覽器
send(connfd,head,strlen(head),0);
while((ret_read = read(fd,read_buf,sizeof(read_buf)))>0)
{
// printf("%s\n",read_buf);
send(connfd,read_buf,ret_read,0);
}
close(connfd);
close(fd);
}
2.main函數
int main(int argc, char *argv[])
{
unsigned int port=8000;//設置端口
if(argc > 1)//可指定端口
{
port = atoi(argv[1]);
}
int sockfd;
struct sockaddr_in my_addr;
// 結構體
memset(&my_addr,0,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(port);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket");
exit(-1);
}
//綁定端口
int err = bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr));
if(err != 0)
{
perror("bind");
close(sockfd);
exit(-1);
}
//監聽端口
err = listen(sockfd,10);
if(err != 0)
{
perror("listen");
close(sockfd);
exit(-1);
}
printf("listen at %d\n",port);
//多線程處理連接請求
while(1)
{
int connfd;//連接套接字
struct sockaddr_in client_addr;
char cli_ip[INET_ADDRSTRLEN]="";
socklen_t cliaddr_len = sizeof(client_addr);
//接受請求
connfd = accept(sockfd,(struct sockaddr *)&client_addr,&cliaddr_len);
if(connfd < 0)
{
perror("accept");
}
//輸出連接者信息
inet_ntop(AF_INET,&client_addr.sin_addr,cli_ip,INET_ADDRSTRLEN);
printf("accepted--ip:%s port:%d\n",cli_ip,ntohs(client_addr.sin_port));
//創建線程
pthread_t pth;
pthread_create(&pth,NULL,msg_echo,(void *)connfd);
pthread_detach(pth);
}
close(sockfd);
return 0;
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。