• Linux—网络编程(day12)


    一、网络基础知识

    二、基于TCP的网络编程


    二、基于TCP的网络编程

    1、编程中用到的辅助函数

    (1)主机字节序和网络字节序的转换

      因为数据存储方式涉及大端和小端,不同方式通信时需要转换,网络字节序为大端;可以使用以下函数:

      #include<arpa.inet.h>

      uint32_t htonl(uint_32_t hostlong);

      uint16_t htons(uint_16_t hostshort);

      uint32_t ntohl(uint_32_t netlong);

      uint16_t nonhs(uint_16_t hostshort);

      其中:h代表host,n代表net,l代表long,s代表short

    (2)具体的网络协议地址空间和通用的网络地址空间的转换。

      具体的网络协议族有ipv4,ipv6,local,unix等,各自有各自的地址空间,通用地址空间的类型为 struct sockaddr类型,在bind,accept等函数中都要用此类型做参数,可使用以下函数做转换:

      inet_pton(3)

      int inet_pton(int af, const char *src, void *dst);

    功能:

      转换src(点分十进制的地址格式)指定的字符串为网络地址结构到af指定的网络地址家族(即text to binary),并拷贝网络地址结构到dst中,af必须指定为AF_INET或者AF_INET 6之一。

    参数:

      af:

        AF_INET

        AF_INET6

      src:点分十进制的字符串IP地址

      dst:转换后的内容,struct in_addr类型(根据af指定协议转换后格式不同,此处以AF_INET为例)

    返回值:

      成功:1

      src不可用:0

      af不可用:-1,errno被设置为EAFNO_SUPPORT

     

     inet_ntop(3)

    const char * inet_ntop(int af, const void *src, char *dst, socklen_t size);    //将数值格式转化为点分十进制的ip地址格式

    功能:

      将在af指定的网络地址空间的src转换为字符串,即将ipv4或ipv6地址从二进制转换到文本结果被拷贝到dst(非空)指定的缓冲区中

    参数:

      

     af:

       AF_INET

       AF_INET6

     src:

      如果指定为AF_INET,则该类型为struct in_addr

     dst:

      字符串地址空间

     size:

      指定了buffer的有效字节数

    返回值:

      错误:NULL,errno被设置

      成功:指向dst的空间的地址

    (3)ipv4的sockaddr_in结构体

    struct sockaddr_in{

      sa_family_t sin_family AF_INET.

      in_port_t sin_port Port number.

      struct in_addr sin_addr IP address.

    }

    另外;struct in_addr至少要包含in_addr_t  s_addr这个成员

    struct sockaddr_in{

      in_addr_t  s_addr;//无符号32位,在inttypes.h中被定义

    }

     2、基于TCP的客户端编程

    (1)使用socket(2)创建铜须描述符

    (2)使用bind(2)绑定端口号与IP地址

    (3)使用connect(2)链接服务器

    (4)数据发送接收

    (5)等待服务器相应

    (6)关闭服务器连接

    connect(2)返回代表客户端的三次握手结束,accept(2)的返回代表服务器的三次握手结束

    connect(2)

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)

    功能:

      把sockfd指定的socket连接到addr指定的地址空间

    参数:  

      sockfd:socket(2)的返回值

      addr:要连接的服务器的地址空间,格式由sockfd决定

      addrlen:addr的大小

    返回值:

      成功:0

      失败:-1,errno被设置

    返回:若成功则为0,若出错则为-1

    基于TCP服务器代码:

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <arpa/inet.h>
    int main()
    {
    int listenfd = socket (AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
        {
            perror ("socket");
            exit (EXIT_FAILURE);
        }
    struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons (8888);
        addr.sin_addr.s_addr = INADDR_ANY;
    if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
        {
            perror ("bind");
            exit (EXIT_FAILURE);
        }
    if (listen (listenfd, 1024) == -1)
        {
            perror ("listen");
            exit (EXIT_FAILURE);
        }
    struct sockaddr_in addrcli = {};
        socklen_t addrlen = sizeof (addrcli);
    int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
    if (connfd == -1)
        {
            perror ("accept");
            exit (EXIT_FAILURE);
        }
        printf ("服务器已接受来自%s:%hu客户机的连接请求
    ", inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
    char buf[1024];
        ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
    if (rcvd == -1)
        {
            perror ("recv");
            exit (EXIT_FAILURE);
        }
    if (rcvd == 0)
        {
            printf ("客户机已关闭连接
    ");
            exit (EXIT_FAILURE);
        }
        buf[rcvd] = '';
        printf ("客户端说:%s
    ", buf);
        printf ("服务器说:");
        gets (buf);
        ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);
    if (sent == -1)
        {
            perror ("send");
            exit (EXIT_FAILURE);
        }
    if (close (listenfd) == -1)
        {
            perror ("close");
            exit (EXIT_FAILURE);
        }
    if (close (connfd) == -1)
        {
            perror ("close");
            exit (EXIT_FAILURE);
        }
    return 0;
    }

    基于TCP的客户端代码:

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <arpa/inet.h>
    int main()
    {
    int listenfd = socket (AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
        {
            perror ("socket");
            exit (EXIT_FAILURE);
        }
    struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons (8888);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
        {
            perror ("connect");
            exit (EXIT_FAILURE);
        }
    char buf[1024] = "你好,服务器";
        printf ("客户端说:%s
    ", buf);
        ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
    if (sent == -1)
        {
            perror ("send");
            exit (EXIT_FAILURE);
        }
        ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);
    if (rcvd == -1)
        {
            perror ("recv");
            exit (EXIT_FAILURE);
        }
        buf[rcvd] = '';
        printf ("服务器说:%s
    ", buf);
    if (close (listenfd) == -1)
        {
            perror ("close");
            exit (EXIT_FAILURE);
        }
    return 0;
    }
  • 相关阅读:
    OpenResty 作者章亦春访谈实录
    linux 下C语言学习路线
    swift 集合类型
    不懂技术的人不要对懂技术的人说这很容易实现
    java学习笔记7--抽象类与抽象方法
    java学习笔记6--类的继承、Object类
    python练习题
    python的里字典和列表
    python里list列表,tuple元组内部功能介绍
    python里float和long内部功能及字符串str介绍
  • 原文地址:https://www.cnblogs.com/ptfe/p/11067959.html
Copyright © 2020-2023  润新知