socket编程相关函数及简单服务器模型

socket编程相关函数及简单服务器模型

1.网络字节序

  • 小端法:高位存高地址,低位存低地址(PC本地存储采用)

  • 大端法:高位存低地址,低位存高地址(网络存储采用)

  • 函数原型:(字节序切换)

    uint32_t htonl(uint32_t hostlong);  //无符号长整型本地字节序转网络字节序
    uint16_t htons(uint16_t hostshort);	//无符号短整型本地字节序转网络字节序
    uint32_t ntohl(uint32_t netlong);   //无符号长整型网络字节序转本地字节序
    uint16_t ntohs(uint16_t netshort);  //无符号短整型网络字节序转本地字节序
    

2.IP地址转换

  • inet_pton函数原型:

    int inet_pton(int af, const char* src, void* dst);
    
  • 功能:本地字节序(string IP)→ 网络字节序

  • 参数:

    af:AF_INET、AF_INET6

    src:传入的点分十进制的参数,传入参数本地IP地址

    dst:传出参数,转换后的网络字节序的IP地址

  • 返回值:

    成功:1

    失败:-1

    异常:0,src指向不是一个有效的ip地址

  • 函数原型:

    const char* inet_ntop(int af, const void* src, char* dst, socklen_t size);
    
  • 功能:网络字节序 → 本地字节序(string IP)

  • 参数:

    af:AF_INET、AF_INET6

    src:网络字节序ip地址

    dst:本地ip地址(string IP)

    size:dst的大小

3.Socket

  • 概念:通信过程中套接字是成对存在的,一个文件描述符指向一个套接字(一个套接字内部由内核借助两个缓冲区实现)。

  • 数据类型及初始化操作

    struct sockaddr_in addr; //新版的套接字结构体
    /*struct sockaddr_in
    {
        sa_family_t    sin_family;  //地址结构类型
        in_port_t      sin_port;    //端口号(网络字节序)
        struct in_addr sin_addr;    //ip地址(网络字节序)
    }
    struct in_addr
    {
    	uint32_t  s_addr;
    }*/
    //初始化各种参数
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9527);
    //int dst;
    //inet_pton(AF_INET, "192.168.1.1", (void*)&dst);
    addr.sin_addr.s_addr = htonl(INADDR_ANY); //取出系统中有效的任意IP地址,二进制类型
    
    struct sockaddr add;     //旧版的套接字结构体(已经淘汰)
    
  • socket函数

    • 原型

      int socket(int domain, int type, int protocol);
      
    • 功能:创建套接字

    • 参数:

      domain:AF_INET、AF_INET6、AF_UNIX表示协议的类型

      type:SOCK_STREAM、SOCK_DGRAM

      protocol:通常为0

    • 返回值:

      成功:新套接字所对应的文件描述符

      失败:-1,errno

  • bind函数

    • 原型

      int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
      
    • 功能:给套接字绑定一个地址结构(IP+port)

    • 参数:

      sockfd:套接字文件描述符

      addr:传入参数,套接字的地址

      addrlen:套接字地址结构长度

    • 返回值:

      成功:0

      失败:-1,errno

  • listen函数

    • 原型:

      int listen(int sockfd, int backlog);
      
    • 功能:设置同时与服务器建立连接的上限数量(同时进行3次握手的客户端数量)

    • 参数:

      sockfd:套接字文件描述符

      backlog:上限数值,最大为128

    • 返回值:

      成功:0

      失败:-1,errno

  • accept函数

    • 原型:

      int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
      
    • 功能:阻塞等待客户端建立连接,成功则返回一个与客户端成功连接的socket文件

    • 参数:

      sockfd:套接字文件描述符,socket函数返回值

      addr:传出参数,传出成功与服务器连接的客户端的地址结构(IP+port)

      addrlen:传入传出参数,入:addr的大小,出:客户端addr的实际大小

    • 返回值:

      成功:能与服务器进行通行的socket对应的文件描述符

      失败:-1,errno

  • connect函数

    • 原型

      int connect(int sockfd, const struct sockaddr* addr, socklen_t 					addrlen);
      
    • 功能:使用现有的socket与服务器建立连接

    • 参数:

      sockfd:socket的返回值,文件描述符

      addr:传入参数,服务器的地址结构

      addrlen:服务器地址结构的长度

    • 返回值:

      成功:0

      失败:-1,errno

  • 注意事项:

  • 如果不用bind绑定客户端地址结构,采用“隐式绑定”

  • tcp的服务器通信流程分析:

    1. socket,创建socket

    2. bind,绑定服务器地址结构

    3. listen,设置监听上限

    4. accept,阻塞监听客户端连接

    5. read,读socket获取客户端数据

    6. toupper,大小写切换

    7. write,向客户端发送数据

    8. close,关闭套接字

  • tcp的客户端通信流程分析:

    1. socket,创建套接字
    2. connect,与服务器建立连接
    3. write,写数据到socket
    4. read,读转换后的数据
    5. close,关闭套接字

4. 多进程高并发服务器

lfd = Socket();   //创建监听套接字
Bind();           //绑定地址结构
Listen();   
while(1)
{
    cfd = Accept();   //接受客户端连接请求
    pid = fork();     //创建子进程
    if(pid == 0)
    {
        //子进程
        close(lfd);
        read(cfd);
        write(cfd);
    }
    else if(pid > 0)
    {
        //父进程
        close(cfd);
        //注册信号捕捉函数
        //回调函数中完成子进程的回收
        continue;
	}
}

5. 多线程并发服务器

lfd = Socket();   //创建监听套接字
Bind();           //绑定地址结构
Listen();   
while(1)
{
    cfd = Accept();    //接受客户端连接请求
    pthread_create();  //创建子线程
    pthread_detach();  //将子线程分离出去可以自动回收
    //创建一个新线程用于专门回收线程
    //pthread_join(tid, void**);
}

//子线程
void* tfn(void* arg)
{
    close(lfd);
    read(cfd);
    write(cfd);
}

6.read函数注意事项

  • 返回值
    1. 大于0:实际读到的字节数
    2. 等于0:已经读到末尾(相当于对端已经关闭套接字)
    3. -1:
      • errno = EAGAIN 或 EWOULDBLOCK:设置了非阻塞模式读,数据没有到达
      • errno = SINTR 慢速系统调用被中断
      • errno = 其他情况异常
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值