从零开始一个http服务器 (一)

代码地址 : https://github.com/flamedancer/cserver

git checkout step1

一个简单的socket server

  • 从helloworld开始
  • 回顾c语言的socket 通信
  • 一个简单的socket server
  • 用telent测试

从helloworld 开始

先来回顾下c语言的,c语言的helloword程序如下

// main.c
#include<stdio.h> int main() {
printf("hello world");
}

编译 gcc main.c

运行 ./a.out

输出 hello world

回顾c语言的socket 通信

socket (server端) 通信的一般 步骤

* 创建 socket , 返回socket 文件描述符,需指明域(本地文件socket还是网络socket),类型(TCP 还是 UDP)
* 绑定 bind, 绑定socket地址(本地socket文件地址 或 网络地址 IP + port)
* 监听 listen, 为socket创建监听队列, 连接到socket的链接将会进入这个队列, 需要指明队列最大长度
* 接收链接 accept, 接收客户端链接,返回接收到的 客户socket文件描述符
* 读写 read/write, 对 客户socket文件描述符 进行 读写操作来进行通信
* close, 通信结束, 关闭 客户socket文件描述符, 整个server结束,也要关闭 server socket文件描述符

c 语言 socket通信有关的函数及结构原型

  1. creating a socket
    #include <sys/types.h> #include <sys/socket.h>
int socket(int domain, int type, int protocol); *** domains
AF_UNIX: 本地文件socket (file system sockets) AF_INET: 网络socket (UNIX network sockets)
...
*** type
SOCK_STREAM: TCP 协议
SOCK_DGRAM: UDP 协议
*** protocol
一般选默认值 0
  1. struct: socket Address socket 地址结构体

    本地文件socket地址:
    AF_UNIX socket_un    defind in sys/un.h
struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[]; // pathname
}; 网络socket 地址:
AF_INET sockaddr_in defind in netinet/in.h
struct sockaddr_in {
short int sin_family; // AF_INET
unsigned short in sin_port; // Port number
struct in_addr sin_addr; // Inernet address
};
其中代表ip地址的结构体in_addr:
struct in_addr {
unsigned long int s_addr;
}
  1. bind

    成功返回0,失败返回-1,失败信息见 errno
    #include <sys/socket.h>
int bind(int socket, const struct sockaddr *address, size_t address_len);
  1. Creating a socket queue
    #include <sys/socket.h>
int listen(int socket, int backlog); // backlog : the maximum number of pending connections
  1. Accept connections

    这里的address和address_len 都是指client端的地址,如果成功连接client,则address被填充

    返回连接后client 的 socket 文件描述符
    #include <sys/socket.h>
int accept(int socket, struct sockaddr *address, size_t *address_len);
  1. Host and Network Byte Ordering

    有可能本地字节编码顺序和网络字节编码顺序不同,本地字节编码要转成网络字节编码
    #include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);

一个简单的socket server

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h> int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建socket,选择地址类型为网络地址,选择 TCP 通信 server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置网络地址的ip, inet_addr 会自动 转为 网络字节顺序
server_address.sin_port = htons(9734); // 设置端口号,注意这里的 htons 方法
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len); listen(server_sockfd, 5);
while(1) {
char ch[5000];
char send_str[] = "hello world !\n"; // 准备给连接过来的客户端发送的字符串
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *)&client_address, &client_len);
read(client_sockfd, &ch, 5000); // 接收 客户端传来的字符
printf("%s", ch); // 打印我们接收到的字符
write(client_sockfd, &send_str, sizeof(send_str)/sizeof(send_str[0])); // 向客户端发送数据,这里的 read write 和 和文件读写时没什么区别
close(client_sockfd);
}
}

和之前helloword一样编译运行我们的第一个版本!

用 telnet 测试

看看效果吧!新启一个终端,然后用telnet 尝试连接我们的服务器。

执行命令 telnet 127.0.0.1 9734

随便输入几个字符按回车

屏幕输出大概为这样:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
dsfsd
hello world !
Connection closed by foreign host.

再返回查看我们的服务器屏幕打印,能看到我们刚才随意输入的字符,说明我们的服务器能成功接收并返回数据了。

从零开始一个http服务器(一)-开始的更多相关文章

  1. 从零开始一个http服务器(六)-多路复用和压力测试

    从零开始一个http服务器(六)-多路复用和压力测试 代码地址 : https://github.com/flamedancer/cserver git checkout step6 运行: make ...

  2. 从零开始一个http服务器(五)-模拟cgi

    从零开始一个http服务器-模拟cgi(五) 代码地址 : https://github.com/flamedancer/cserver git checkout step5 运行: make cle ...

  3. 从零开始一个http服务器(三)-返回response 构造

    从零开始一个http服务器(三) 代码地址 : https://github.com/flamedancer/cserver git checkout step3 运行: gcc request.h ...

  4. 从零开始一个http服务器(二)-请求request解析

    从零开始一个http服务器 (二) 代码地址 : https://github.com/flamedancer/cserver git checkout step2 解析http request 观察 ...

  5. 从零开始一个http服务器(四)-动态返回

    从零开始一个http服务器(四) 代码地址 : https://github.com/flamedancer/cserver git checkout step4 运行: make clean &am ...

  6. 在阿里云服务器(ECS)上从零开始搭建nginx服务器

    本文介绍了如何在阿里云服务器上从零开始搭建nginx服务器.阿里云服务器(ECS)相信大家都不陌生,感兴趣的同学可以到http://www.aliyun.com/product/ecs去购买,或到体验 ...

  7. Linux下配置一个VNC服务器

    在Linux下配置一个VNC服务器,并设置2个用户,要求其中一个用户登录时不需要输入密码. 然后在客户端使用ssh+vncview的方式访问. 1确认vnc安装 2配置vncserver 3测试vnc ...

  8. 在 Linux 上配置一个 syslog 服务器

    syslog服务器可以用作一个网络中的日志监控中心,所有能够通过网络来发送日志的设施(包含了Linux或Windows服务器,路由器,交换机以及其他主机)都可以把日志发送给它. 通过设置一个syslo ...

  9. nodejs创建一个HTTP服务器 简单入门级

    const http = require('http');//请求http.createServer(function(request, response){    /*createServer该函数 ...

随机推荐

  1. [使用教程]cocostudio之UI编辑器动画模式

    有坑! 1. 使用 (1)点击动画模式按钮,进入动画模式 (2)[关键1]左下角动作列表,右键添加动画 (3)[关键2]渲染区选择要动画的控件,右键编辑动画 * 可以看到最下面多了关键帧 (4)在右边 ...

  2. Python初学者第八天 元组和字典

    8day 1.数据类型:元组 元组:有序的,不可变地数据的集合.但若包含其他可变元素,这些元素可变.显示的告诉别人,此处不可修改: a = (1,2,3,4,5,['1','a']) 2.数据类型:字 ...

  3. 应用线性代数简介 - 向量,矩阵和最小二乘法 By Stephen Boyd and Lieven Vandenberghe

    Introduction to Applied Linear Algebra – Vectors, Matrices, and Least Squares 应用线性代数简介 - 向量,矩阵和最小二乘法 ...

  4. Bash命令行 bash &> >& Bash One-Liners Explained

    Bash One-Liners Explained, Part I: Working with files https://catonmat.net/bash-one-liners-explained ...

  5. Spring-aop实现切面的四种方式 (2)

    AOP实现方式一 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http ...

  6. 连接IBM MQ原因码报2035的错误解决办法

    我们的系统使用了ibm mq,用户用来向国家局上报文件和接收文件,前几天用户说上报一直不成功.由于 开发这块程序的人已经辞职了,我觉定在我的机器部署一套,研究一下.我的思路: 在我的机器上安装mq,建 ...

  7. 关于Hibernate多对多关联关系的更新问题。

    一个账套类Reckoning和账套项目类 AccountItem.这两个类是双向多对多关联关系. Reckoning.hbm.xml文件的配置如下 <set name="account ...

  8. BZOJ5293:[BJOI2018]求和(LCA,差分)

    Description master 对树上的求和非常感兴趣.他生成了一棵有根树,并且希望多次询问这棵树上一段路径上所有节点深度的k  次方和,而且每次的k 可能是不同的.此处节点深度的定义是这个节点 ...

  9. 如何设置活动监视器中的可见作业数能显示更长范围之内的作业(如何让bpdbjobs/Active Monitor显示更多作业信息)

    一.问题:     如何设置可以使得活动监视器中的可见作业数能显示更长范围之内的作业(即NBU软件不要自动删除活动监视器中短时间内(如8天)内的作业记录)? 二.解决方法:      默认情况下在Ac ...

  10. Mac--查看公钥

    打开macbook的终端输入以下命令: $ cd ~/.ssh $ ls $ cat id_rsa.pub