高并发服务器编写


高并发服务器编写

大小端

大端:(Big-Endian):就是把数值的高位字节放在内存的低位地址上,把数值的低位字节放在内存的高位地址上。

小端:(Little-Endian):就是把数值的高位字节放在高位的地址上,低位字节放在低位地址上。

  • 通常在计算机中为小端
  • 网络里面为大端

测试

serv_addr.sin_port = htons(8193);
printf("%d\n", htons(SERVER_PORT));

输出为288

>>> bin(8193)[2:].zfill(16)
'0010000000000001'
>>> bin(288)[2:].zfill(16)
'0000000100100000'

c中的函数

#include <arpa/int.h>
  • inet_pton
  • inet_ntop

大小端转化

普通转化(unsing int -> int)
#include <arpa/inet.h>
  • uint32_t htonl(uint32_t hostlong);
  • uint16_t htons(uint16_t hostshort);
  • uint32_t ntohl(uint32_t netlong);
  • uint16_t ntohs(uint16_t netshort);
ip转化(string -> int)
#include <arpa/inet.h>
  • int inet_pton(int af, const char *src, void *dst);
  • const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

p -> 字符串, n -> network

ntop需要多传socklen_t

sockaddr

sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了,如下:

struct sockaddr {
        u_short sa_family;              /* address family */
        char    sa_data[14];            /* up to 14 bytes of direct address 包含套接字中的目标地址和端口地址 */
};

但由于历史原因, bind, accept, connect函数传参需要强制转化为其指针

sockaddr_in

由于sockaddrip和端口区分不够细致, 因此用sockaddr_in来定义, 但传参需要强制转化为sockaddr

struct sockaddr_in serv_addr, clie_addr;

sockaddr_in在头文件#include<netinet/in.h>#include <arpa/inet.h>中定义

struct sockaddr_in {
        short   sin_family;         //address family
        u_short sin_port;           //16 bit TCP/UDP port number
        struct  in_addr sin_addr;   //32 bit IP address
        char    sin_zero[8];        //not use, for align
};

其中in_addr结构体定义了32bit的ip地址, 定义如下

//
// IPv4 Internet address
// This is an 'on-wire' format structure.
//
typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;
#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

sock

lfd = socket(AF_INET, SOCK_STREAM, 0);
#include <sys/types.h> 
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • 第一个参数为地址族, AF_INET``AF_INET6常用(为”Address Family INET是“Inetnet”)
  • type 为数据传输方式,常用的有 SOCK_STREAM 和 SOCK_DGRAM,在《socket是什么意思》一节中已经进行了介绍
  • protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。

bind

#include <sys/types.h> 
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen

#include <sys/types.h> 
#include <sys/socket.h>
int listen(int sockfd, int backlog);

accept

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

connect

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 返回新的socket文件描述符
  • 第三个参数为传入传出参数

socklen_t

int差不多

BUFSIZ

宏定义了, 大小为8k

server.c

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <ctype.h>
#include <arpa/inet.h>

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8193

int main(){
    int lfd, cfd;
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    char buf[BUFSIZ];
    int n;

    lfd = socket(AF_INET, SOCK_STREAM, 0);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERVER_PORT);
    printf("%d\n", htons(SERVER_PORT));
    // serv_addr.sin_addr.s_addr = htonl(SERVER_IP);
    serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

    bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(lfd, 128);

    clie_addr_len = sizeof(clie_addr);
    cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);

    while(1){
        n = read(cfd, (struct sockaddr *)buf, sizeof(buf));
        for (int i = 0; i < n; i++)
            buf[i] = toupper(buf[i]);
        write(cfd, buf, n);
    }

    close(lfd);
    close(cfd);

    return 0;
}

  TOC