• linux c编程:网络编程


    在网络上,通信服务都是采用C/S机制,也就是客户端/服务器机制。流程可以参考下图:

    服务器端工作流程:

    使用socket()函数创建服务器端通信套接口

    使用bind()函数将创建的套接口与服务器地址绑定

    使用listen()函数使服务器套接口做好接收连接请求准备

    使用accept()接收来自客户端由connect()函数发出的连接请求

    根据连接请求建立连接后,使用send()函数发送数据,或者使用recv()函数接收数据

    使用closesocket()函数关闭套接口(可以先用shutdown()函数先关闭读写通道)



    客户端程序工作流程:

    使用socket()函数创建客户端套接口

    使用connect()函数发出也服务器建立连接的请求(调用前可以不用bind()端口号,由系统自动完成)

    连接建立后使用send()函数发送数据,或使用recv()函数接收数据

    使用closesocet()函数关闭套接口

    下面介绍几个函数的用法:

    socket函数:int socket(int domain,int type,int protocol)

    参数说明:
    domain:
    指明协议族,也称为协议域,是一个常值。
    AF_INET:IPv4
    协议
    AF_INET6:IPv6
    协议
    AF_LOCAL/AF_UNIX:Unix
    协议域
    AF_ROUTE:
    路由套接字
    AF_KE:
    密匙套接字

    type
    :指明套接字的类型。
    SOCK_STREA:
    字节流套接字
    SOCK_DGRA:
    数据报套接字
    SOCK_SEQPACKE:
    有序分组套接字
    SOCK_RAW:
    原始套接字

    protocol:
    指明协议类型。一般为0,以选择给定的domaintype组合的系统默认值。
    IPPROTO_TCP:TCP
    传输协议
    IPPROTO_UDP:UDP
    传输协议
    IPPROTO_SCTP:SCTP
    传输协议

    函数描述:
    socket
    函数在成功时返回一个小的非负整数值,与文件描述符类似,我们称它为套接字
    描述符,简称 sockfd。为了得到这个套接字描述符,我们只是指定了协议族(IPv4IPv6
    Unix)和套接字类型(字节流、数据报或原始套接字)。我们并没有指定本地跟远程的
    协议地址

    bind函数:int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

    将一个本地协议地址赋予一个套接字。对于网际网协议,协议地址是32位的IPv4地址和128
    位的IPv6地址与16位的TCPUDP端口号的组合。bind 函数主要用于服务器端,用来指定本地
    主机的哪个网络接口(IP,可以是INADDR_ANY,表示本地主机的任一网络接口)可以接受客户
    端的请求,和指定端口号(即开启的等待客户来连接的进程)。

    参数说明:

    sockfd: socket 函数返回的套接字描述符。

    myaddraddrlen:指向一个套接字地址结构的指针和该结构的大小。

    地址结构的一般采用sockadr_in结构体

    struct sockaddr_in{

    short int sin_family; #地址族

    unsigned short int sin_port; #端口号

    struct n_addr sin_addr; #IP地址

    unsigned char sin_zeor[8]; #填充0保持与struct sockaddr同样大小

    }

    listen函数:

    int listen(int sockfd,int backlog)

    listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

    Connetc函数:

    connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接



    accept函数:

    int accept(int sockfd,struct sockaddr *addr, socketen_t *add_len)

    参数sockfd
    参数sockfd就是上面解释中的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用这个一个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。
    参数addr
    这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL
    参数len
    如同大家所认为的,它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL

    如果accept成功返回,则服务器与客户已经正确建立连接了,此时服务器通过accept返回的套接字来完成与客户的通信。

    服务器测的代码如下:对于服务端来说,首先是建立socket然后绑定IP地址到socket上。然后开始监听。

    当接收到请求的时候,通过recv函数存储在buf数组里面。并且通过send函数向对端发送消息

    int server_function()
    {
        char *sendbuf="thanks";
        char buf[256];
        int s_fd,c_fd;
        int s_len,c_len;
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;
        s_fd=socket(AF_INET,SOCK_STREAM,0);
        s_addr.sin_family=AF_INET;
        s_addr.sin_addr.s_addr=htonl(INADDR_ANY);
        s_addr.sin_port=PORT;
        s_len=sizeof(s_addr);
        bind(s_fd,(struct sockaddr *)&s_addr,s_len);
        listen(s_fd,10);
        while(1){
            printf("please wait a moment ");
            c_len=sizeof(c_addr);
            c_fd=accept(s_fd,(struct sockaddr *)&c_addr,(socklen_t *__restrict)&c_len);
            recv(c_fd,buf,256,0);
            buf[strlen(buf)+1]='';
            printf("receve message: %s ",buf);
            send(c_fd,sendbuf,strlen(sendbuf),0);
            close(c_fd);
        }
    }

    客户端的代码如下:设置好连接的IP地址和端口后,通过connect发起连接。并通过sendrecv函数进行发送和接收消息

    int client_function()
    {
        char *buf="come on";
        char rebuf[250];
        int sockfd,len,newsockfd,len2;
        struct sockaddr_in addr;
        sockfd=socket(AF_INET,SOCK_STREAM,0);
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=htonl(INADDR_ANY);
        addr.sin_port=PORT;
        len=sizeof(addr);
        newsockfd=connect(sockfd,(struct sockaddr *)&addr,len);
        len2=strlen(buf);
        send(sockfd,buf,len2,0);
        sleep(5);
        recv(sockfd,rebuf,40,0);
        printf("the length of the rebuf is %d",strlen(rebuf));
        rebuf[strlen(rebuf)+1]='';
        printf("receive message: %s ",rebuf);
        close(sockfd);
        return 0;
    }

    打开2个终端,分别运行服务器和客户端的代码。执行结果如下:

  • 相关阅读:
    Linux查看占用内存前10的命令
    使用RestTemplate调用SpringCloud注册中心内的服务
    Eureka集群配置
    MySQL常用命令集合(偏向运维管理)
    pytest: error: unrecognized arguments报错解决
    MongoDB的安装
    MongoDB多条件分组聚合查询
    在排序数组中查找元素的第一个和最后一个位置
    搜索二维矩阵
    搜索旋转排序数组
  • 原文地址:https://www.cnblogs.com/zhanghongfeng/p/7802728.html
Copyright © 2020-2023  润新知