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

从零开始一个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.

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

原文地址:https://www.cnblogs.com/chens-smile/p/9462510.html

时间: 2024-10-24 15:55:41

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

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

从零开始一个http服务器-模拟cgi(五) 代码地址 : https://github.com/flamedancer/cserver git checkout step5 运行: make clean && make && ./myserver.out 测试 浏览器打开 http://127.0.0.1:9734/action/show_date 模拟cgi:用外部程序来优化 动态 response cgi解释 调用外部程序 cgi解释 上一节中,我们确实是实现了动态的

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

本文介绍了如何在阿里云服务器上从零开始搭建nginx服务器.阿里云服务器(ECS)相信大家都不陌生,感兴趣的同学可以到http://www.aliyun.com/product/ecs去购买,或到体验馆去体验(半个月有效期).至于如何注册.管理ECS这里就不详细介绍了.因为官方文档已经写的很清楚了.如果还不清楚,打咨询电话询问. 现在假设你已经拥有了阿里云服务器,ip是139.128.33.11(假的,读者需要换成自己的ip地址).并且没有选择任何安装包.现在ECS是完全空的,除了必须的Linu

一个让服务器CPU飙升的BUG。找了2天才发现。

昨天升级了站点.发现一升级上去,就发现站点服务器CPU开始占用接近100%.但是数据库服务器变化不大 还原回更新之前的代码.立马CPU降低.一开始已经是增加的缓存机制有了问题,采用数据库读取,放到线上依旧. 接着以为是数据统计有问题,删除掉还是一样.最后的最后,通过看到工作线程,发现登录请求也蛮多的. 然后这个登录代码更新到旧版本.就OK了.这次版本对登录进行了重构.直接上代码 错误代码中 登录后直接是使用了user.BbbID,造成了500错误.IIS对这个500错误也会有CPU损耗.于是就飙

FreeSWITCH折腾笔记4——自己做一个TTS服务器

freeswitch原生支持的tts功能中文一般是使用的ekho,但是那合成的效果简直惨不忍睹,于是我想自己做一个TTS服务器. 首先是找到比较满意的TTS引擎,科大讯飞的效果当然是没话说,但是价格不菲,其他商业的引擎中文合成也不是很流畅,偶然发现windows7自带的合成引擎还算过得去,windows10带的合成引擎就更好了(有兴趣的可以先测试一下,直接在windows控制面板中的语音设置里面有测试,但是测试的中英文混读很蛋疼). 那么问题来了,怎么把这个引擎用到我的FS上边呢? 思路,deb

在Linux中搭建一个FTP服务器

在Linux中搭建一个ftp服务器,以供两个工作小组保管文件使用.禁用匿名.第一个小组使用ftp账号:ftp1,工作目录在:/var/ftp/ftp1:第二个小组使用ftp2,工作目录在:/var/ftp/ftp2. 两个小组互相不能访问各自的文件,需要限制用户不能离开自己的工作目录. [实现步骤] 1.检查安装vsftpd服务器 以root进入终端后(其他账户进入终端的可以用su root 输入密码后进入root 模式)之后,在终端命令窗口输入以下命令进行验证:# rpm –qa | grep

在 Linux 上配置一个 syslog 服务器

syslog服务器可以用作一个网络中的日志监控中心,所有能够通过网络来发送日志的设施(包含了Linux或Windows服务器,路由器,交换机以及其他主机)都可以把日志发送给它. 通过设置一个syslog服务器,可以将不同设施/主机发送的日志,过滤和合并到一个独立的位置,这样使得你更容易地查看和获取重要的日志消息. rsyslog 作为标准的syslog守护进程,预装在了大多数的Linux发行版中.在客户端/服务器架构的配置下,rsyslog同时扮演了两种角色:1.作为一个syslog服务器,rs

写一个ftp服务器(1)--需求分析

一个ftp服务器要有什么功能,拿vsftpd举例来说,vsftpd除了实现基本的ftp命令,还支持控制连接,参数可配置,断点续传等. vsftpd的大部分配置及功能可以在其配置文件中看到 Linux下执行 man 5 vsftpd.conf查看. 假如自己实现一个ftp服务器,要实现的功能如下: 1.标准ftp命令 基本的ftp文件传输协议,可以参考RFC 这里收录了一个中文简化版本:https://github.com/zilandy/zFTP 下doc 2.参数配置 通过配置文件改变执行参数

用C写一个web服务器(二) I/O多路复用之epoll

.container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .container::before,.container::after { content: " "; display: table } .container::after { clear: both } .container::before,.container::after { content:

初学node,js入门篇(1) ========搭建第一个node服务器

闲来无事,研究一番node.js,虽然网上已有大把的资源教程,但是还是不如自己手写一份来的记忆深刻. 创建node服务器第一步:下载node.js安装以及配置环境变量. 创建node服务器第二步:找到node.js的根目录,盘符:\nodejs\node_modules   这是node.js的根目录. 创建node服务器第三步:创建一个新的js文件,例如server.js,放置在node_modules目录下面. 创建node服务器第四步:编辑server.js文件,具体代码如下 //引入re