这是一个关于socket的题:要求你自己写一个socket程序,然后解析客户端从浏览器地址栏提交的数据。
要求:在浏览器中输入http://localhost:8500 后,你的socket程序向浏览器返回一个网页,以后就用这个网页向你写得这个socket程序提交数据,你的socket程序负责解析这些数据关回答到那个网页上去。
涉及的知识点:1. socket编程; 2.http请求与响应;
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<sys/socket.h> #include<sys/wait.h> #include<sys/fcntl.h>
#define PORT 8500//端口号 #define BACKLOG 5/*最大监听数*/
int main(){ char* trim(char* str);
int sockfd,new_fd;/*sockfd是监听套接字,new_fd是通信套接字*/ struct sockaddr_in my_addr;/*本方地址信息结构体,下面有具体的属性赋值*/ struct sockaddr_in their_addr;/*对方地址信息*/ socklen_t sin_size; char mybuf_1[520] = { 0 };//本socket要返回给网页的信息 char* get_value[10];
sockfd=socket(AF_INET,SOCK_STREAM,0);//获得监听套接字 if(sockfd==-1){ printf("socket failed:%d",errno); return -1; } my_addr.sin_family=AF_INET;/*协议簇*/ my_addr.sin_port=htons(PORT);/*端口号*/ my_addr.sin_addr.s_addr=htonl(INADDR_ANY);/*IP,括号内容表示本机IP*/ bzero(&(my_addr.sin_zero),8);/*将其他属性置0*/ if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))<0){//绑定地址结构体和socket printf("bind error"); return -1; } listen(sockfd,BACKLOG);//开启监听 ,第二个参数是最大监听数
int number = 0; while(1){ sin_size=sizeof(struct sockaddr_in); new_fd=accept(sockfd,(struct sockaddr*)&their_addr,&sin_size);//在这里阻塞知道接收到消息,参数分别是socket句柄,接收到的地址信息以及大小 if(new_fd==-1){ printf("receive failed"); } else { char request[1024]; recv(new_fd, request, 1024, 0); request[strlen(request) + 1] = '\0'; printf("%s", request); printf("网页请求数据接收成功!\n");
//如果是第一次接受请求,就向网页发送响应网址exec.html //number 代表网页发请求的次数 if (number == 0) { //char buf[520] = "HTTP/1.1 200 ok\r\nconnection: close\r\n\r\n";//HTTP响应 char buf[520] = "HTTP/1.1 200 ok\r\n\r\n";//HTTP响应 int s = send(new_fd, buf, strlen(buf), 0);//发送响应 int f1 = open("exec.html", O_RDONLY);//消息体 sendfile(new_fd, f1, NULL, 2500);//零拷贝发送消息体 close(f1); close(new_fd); } else { int m = 0; /*下面是我对请求协议的解析*/ char* p1 = NULL;//p1代表获取到的网页请求信息中第一行 p1 = strtok(request, "\r\n"); //p1的结果是: GET /?aaa=18&b=99 HTTP/1.1
char* p2 = NULL;//p2代表网页请求信息中的第二行,即网址部分,应该是以空格分割的第二个数据 p2 = strtok(p1, " "); while (p2 != NULL) { if (m == 1) { break; } p2 = strtok(NULL, " "); m++; } printf("%s\n", p2); // p2的结果要么是 / ,要么是 /?aaa=18&b=99
char* p3 = NULL;//请求网址中的变量部分 p2 = trim(p2); //去除p2前后的空格 if (strcmp(p2, "/") == 0) { strcpy(mybuf_1, "请输入get数据\n"); char buf[520] = "HTTP/1.1 200 ok\r\n\r\n";//HTTP响应 int s = send(new_fd, buf, strlen(buf), 0);//发送响应 int s1 = send(new_fd, mybuf_1, strlen(mybuf_1), 0);//发送响应 close(new_fd); } else { p3 = strtok(p2, "?"); m = 0; while (p3 != NULL) { if (m == 1) { break; } p3 = strtok(NULL, "?"); m++; } printf("%s\n", p3); // 得到的数据是这样的形式: aaa=18&b=99
//下面是对aaa=18&b=99这样的数据用&进行拆分 char* v[15]; char* p4 = NULL; m = 0; if (p3 != NULL) { p4 = strtok(p3, "&"); while (p4) { v[m] = p4; ++m; p4 = strtok(NULL, "&"); } } printf("共get了%d个参数\n", m); printf("以下是get提交的数据,分别取出来后存放在get_value[]中\n"); int j; int z = 0; for (j = 0; j < m; ++j) { printf("v数组的数据是:%s\n", v[j]); char* p5 = NULL; if (v[j] != NULL) { p5 = strtok(v[j], "="); while (p5) { get_value[z] = p5; ++z; p5 = strtok(NULL, "="); } } } printf("get_value的数据分别是:\n"); for (j = 0; j < z; j++) { printf("%s\n", get_value[j]); } printf("get_value[1]= %s\n", get_value[1]);
if (strcmp(get_value[1], "cat+test") == 0) { char buf[520] = "HTTP/1.1 200 ok\r\n\r\n";//HTTP响应 int s = send(new_fd, buf, strlen(buf), 0);//发送响应 int f1 = open("test.txt", O_RDONLY);//消息体 sendfile(new_fd, f1, NULL, 2500);//零拷贝发送消息体 close(f1); close(new_fd); } else { /*把数字转成字符串时,不能用itoa(),linux C它不认*/ char buf[520] = "HTTP/1.1 200 ok\r\n\r\n";//HTTP响应 int s = send(new_fd, buf, strlen(buf), 0);//发送响应 char* buffer = get_value[1]; //strcat(mybuf_1, buffer); strcpy(mybuf_1, buffer); int s1 = send(new_fd, mybuf_1, strlen(mybuf_1), 0);//发送响应 close(new_fd); //下面是把数字转成字符串。不能用itoa(),因为linux c不认 //char buffer[12] = { 0 }; //snprintf(buffer, 3, "%d", number); //strcat(mybuf_1, buffer); }
}
} } number++; } return 0; }
//去除尾部空格 char* rtrim(char* str) { if (str == NULL || *str == '\0') { return str; }
int len = strlen(str); char* p = str + len - 1; while (p >= str && isspace(*p)) { *p = '\0'; --p; }
return str; }
//去除首部空格 char* ltrim(char* str) { if (str == NULL || *str == '\0') { return str; }
int len = 0; char* p = str; while (*p != '\0' && isspace(*p)) { ++p; ++len; }
memmove(str, p, strlen(str) - len + 1);
return str; }
//去除首尾空格 char* trim(char* str) { char* rtrim(char* str); char* ltrim(char* str); str = rtrim(str); str = ltrim(str);
return str; }