嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2015-10-13 3932 次浏览 标签 : Linux

目前我自己工作中一部分使用的是 nginx 做的 web 服务器,一部分是直接使用 netty 做 api 服务器(我只是使用 netty 强大功能的冰山一角吧)。

先复习下之前自己的笔记:

使用 php 实现 socket 通信

使用 php 实现静态 web 服务器和动态 web 服务器

希望自己也能够对 socket api 有更加深刻和透彻的认识。

首先还是先用 c 来实现 socket 通信

基础知识储备

  1. socket通信的原理(如下图所示)

  2. sockaddr_insockaddr的了解

  3. 大端序,小端序,网络字节序

  4. 地址转换函数

原理如图:

简单的 socket 通信

在 linux 里,执行man 7 ip就能看到socket基础编程很全面的说明了,比如sockaddr_in的数据结构

struct sockaddr_in {
   sa_family_t    sin_family; /* address family: AF_INET */
   in_port_t      sin_port;   /* port in network byte order */
   struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr {
   uint32_t       s_addr;     /* address in network byte order */
};

man手册里面好像写的不完整,对比下sockaddr_insockaddr的区别

/* sockaddr_in 的定义在 /usr/include/netinet/in.h */

/* Structure describing an Internet socket address.  */
struct sockaddr_in {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;                 /* Port number.  */
    struct in_addr sin_addr;            /* Internet address.  */

    /* Pad to size of `struct sockaddr`.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                           __SOCKADDR_COMMON_SIZE -
                           sizeof (in_port_t) -
                           sizeof (struct in_addr)];
};

/* scokaddr 的 定义在 /usr/include/linux/socket.h */

#define _K_SS_MAXSIZE   128     							/* Implementation specific max size */
#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *)) 	/* Implementation specific desired alignment */

struct __kernel_sockaddr_storage {
        unsigned short  ss_family;              							/* address family */
		/* Following field(s) are implementation specific */
        char            __data[_K_SS_MAXSIZE - sizeof(unsigned short)];		/* space to achieve desired size, */
                                											/* _SS_MAXSIZE value minus size of ss_family */
} __attribute__ ((aligned(_K_SS_ALIGNSIZE)));   /* force desired alignment */

sockaddr定义里面宏太多,没看太明白,反正需要记住,sockaddr_in是我们网络编程使用的结构,而在做内核调用的时候,需要将其转换成sockaddr才行。

代码编写环境 Centos ,服务端代码 server.c 如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define SERV_PORT 8031
int main(void)
{
    int lfd, cfd; // 文件描述符
    struct sockaddr_in serv_addr,clin_addr; // 服务器端和客户端 socket 地址
    socklen_t clin_len;
    char buf[1024];
    int len;    //读取的客户端的数据长度

    // AF_INET          IPV4 
    // SOCK_STREAM      stream 协议
    // 0                tcp
    lfd = socket(AF_INET,SOCK_STREAM,0);
    
    serv_addr.sin_family = AF_INET;//IPV4
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);// 设置 ip 绑定本地的 INADDR_ANY (任意一个 ip,可能有多个网卡)
    serv_addr.sin_port = htons(SERV_PORT);// 设置端口  网络序 - 大端存储 - 计算机组成原理
    
    // ip+port  泛型指针 void *
    bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    
    listen(lfd, 128);

    clin_len = sizeof(clin_addr);
    cfd = accept(lfd, (struct sockaddr *)&clin_addr, &clin_len);
    len = read(cfd,buf,sizeof(buf));
    write(STDOUT_FILENO,buf,len);

    close(lfd);
    close(cfd);

    return 0;
}

首先,通过 gcc 编译 server.c 文件,使用命令gcc server.c -o server,则会在当前目录生成一个可执行文件server

然后,通过命令./server让其运行起来。

最后,我在远程通过 nc 命令连接到服务器 nc 10.211.55.4 8031连接到服务器,依照程序的设计,这时候,当我在客户端输入字符串回车之后,服务器端会收到该内容并且在屏幕上打印出来。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表