重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
网络骇客入门之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
#include
#include
#include
#include
#include
#include
#include
#include
//子线程处理浏览器的网页请求
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" \
"
File not found";
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;
}