Skip to content

Latest commit

 

History

History
65 lines (50 loc) · 2.11 KB

01server_sock.md

File metadata and controls

65 lines (50 loc) · 2.11 KB

创建Socket并监听端口

创建Socket:

int startup(u_short* port) {
  int httpd = -1;
  // IPv4: PF_INET 和AF_INET基本一致, 推荐写AF_INET
  // SOCK_STREAM 指TCP协议, SOCK_DGRAM 指UDP
  // 最后一位为保留位
  httpd = socket(AF_INET, SOCK_STREAM, 0);
  if (httpd == -1) error_die("socket");

  // 设置绑定数据
  struct sockaddr_in name;
  memset(&name, 0, sizeof(name));
  // 确定协议簇为IPV4
  name.sin_family = AF_INET;
  // 配置绑定地址为本机开放地址
  name.sin_addr.s_addr = htonl(INADDR_ANY);
  // 配置传入的端口
  name.sin_port = htons(*port);
  // 绑定Socket和配置项
  if (bind(httpd, &name, sizeof(name)) < 0) error_die("bind");
  // 启动监听动作
  if (listen(httpd, 5) < 0) error_die("listen");

  return httpd;
}

h代表host主机、n代表net网络、l代表long长整型、s代表short短整形。

htonl/htons/ntohl/ntohs 是用于转换字节顺序的函数。计算机内一般是小端存储: 0x12345678, 最左侧的0x78存储在高位;网络发送时,用的是大端模式。

在绑定过程,如果发现*port == 0, 则说明端口没有绑定成功,需要使用int(*getsockname)(int, struct sockaddr*, int*)函数请求系统给httpd分配端口

  if (bind(httpd, &name, sizeof(name)) < 0) error_die("bind");

+ if (*port == 0) {
+   int name_len = sizeof(name);
+   if (getsockname(httpd, &name, &name_len) < 0) error_die("getsockname");
+   // 得到可用的port后回填到参数中
+   *port = ntohs(name.sin_port);
+ }

int(*listen)(int socket, int backlog)方法中,第二个填写为5,理由是未连接队列和已完成TCP握手队列数,上限是5,所以就填5了。

创建Socket直接使用方法int(*socket)(int, int, int)即完成, 接下来绑定(bind)使用的协议族(ipv4/ipv6)、端口、地址, 以及最后的发出监听(listen)。

测试

gcc -o app server_sock.c
./app // 打印出端口号说明成功

下一章

浏览器连接并打印请求头信息