Socket Server 的核心流程的一点解释
socket -> bind -> listen -> accept -> read -> write -> close
后面的 read->write->close
比较好理解. 对于这个 socket->bind->listen->accept
我们则需要重点关注一下:
Socket Server ,也就是网络编程中的服务端. 一开始是以接话员的逻辑来设计的.比如 12580
的客服.
-
socket
调用相当于招聘了一个客服. -
bind
给客服分配了具体的岗位和号码 . -
listen
客服上岗,开始在电话前等咨询电话进来. -
accept
显然这是拿起电话开始服务.
值得注意的是 accept
才是阻塞的.它会一直阻塞直到有连接进来. 我们上面的设计是比较简单的.
实际上设计更复杂,比如accept
进来交给新的进程,线程,协程等去处理.然后这里继续接收新的连接进来.
C/C++ 语言本身没有socket,要调用操作系统的API, Windows和Linux的API还不同。
Python和Go的语言本身就有API,而且要比C简单很多。
但大体上,首先创建,然后绑定,然后监听,然后accpet这个步骤是不会变的。
这些步骤并不需要记忆,用到的时候去查API手册即可。
HTTP协议本质上就是服务器向客户端发送文本类型(html)的数据,浏览器解析渲染。
HTTP响应并不需要一次发送完,可以发送多次,如下所示:
const char body[] =
"<h1 style=\"color:red;\">欢迎来到代码会说话的编程世界!</h1>\r\n";
const char headers[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type:text/html;charset=utf-8\r\n"
"Content-Length:75\r\n"
"Connection: close\r\n"
"\r\n";
while (true) {
int clientfd =
accept(serverfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (CHECK_FAIL(clientfd)) {
return -1;
}
char *client_ip = inet_ntoa(client_addr.sin_addr);
printf("client connected: %s:%d\n", client_ip, ntohs(client_addr.sin_port));
ssize_t send_cnt = -1;
send_cnt = write(clientfd, headers, sizeof(headers));
if (CHECK_FAIL(send_cnt)) {
continue;
}
send_cnt = write(clientfd, body, sizeof(body));
if (CHECK_FAIL(send_cnt)) {
continue;
}
ret = close(clientfd);
CHECK_FAIL(ret);
}