• linux 网络编程


    linux网络编程中主要分为服务器和客户端两部分,而网络编程中又分为TCP和UDP两种。
    TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议。
    TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流,TCP套接口是字节流套接口(stream socket)的一种。
    UDP:用户数据报协议。UDP是一种无连接协议。UDP套接口是数据报套接口(datagram socket)的一种。

     

    ============================================TCP=======================================
    A、建立服务器的步骤(TCP):
    (1)创建TCP套接字: socket(int domain, int type, int protocol);

    (2)设置端口号和IP: struct sockaddr_in (本结构体包含端口号和IP等信息)

    (3)绑定套接字与网络地址 : bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

    (4)将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数:listen(int socket, int backlog);

    (5)等待客户端连接的请求:accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    (6)进行通信:recv(int sockfd, void *buf, size_t len, int flags);或用read()也可以

    (7)关闭套接字:int close(int fildes);


    B、建立客户端(TCP):
    (1)创建TCP套接字:socket(int domain, int type, int protocol);

    (2)设置服务器的IP与端口号:struct sockaddr_in (本结构体包含端口号和IP等信息)

    (3)发送连接请求:connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

    (4)进行通信:send(int sockfd, const void *buf, size_t len, int flags);或用write()也可以

    (5)关闭套接字:int close(int fildes);


    ==========================================UDP========================================
    A、建立服务器的步骤(UDP):
    (1)创建UDP套接字: socket(int domain, int type, int protocol);

    (2)设置端口号和IP: struct sockaddr_in (本结构体包含端口号和IP等信息)

    (3)绑定套接字与网络地址 : bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

    (4)进行通信:recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

    (5)关闭套接字:int close(int fildes);

    B、建立客户端(UDP):
    (1)创建UDP套接字: socket(int domain, int type, int protocol);

    (2)设置端口号和IP: struct sockaddr_in (本结构体包含端口号和IP等信息)

    (3)进行通信:sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

    (4)关闭套接字:int close(int fildes);



    一、创建套接字

    1、头文件 #include <sys/types.h>          /* See NOTES */
                      #include <sys/socket.h>

    2、接口声明 int socket(int domain, int type, int protocol);
    参数:
    a、domain:
    AF_INET / PF_INET :网际协议
    AF_UNIX / PF_UNIX :本地协议

    b、type:
    SOCK_STREAM :流式套接字(TCP)
    SOCK_DGRAM :数据报套接字(UDP)

    c、protocol:协议
    一般写为0 :当protocol为0时,会自动选择type类型对应的默认协议。

    3、返回值:
    成功:等待连接的套接字
    失败:-1


    二、绑定套接字与网络地址

    1、头文件 #include <sys/types.h> /* See NOTES */
                     #include <sys/socket.h>

    2、接口声明 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

    参数:
    a、sockfd:等待连接套接字
    b、addr:包含本地地址(IP+PORT)的通用地址结构体的指针
    c、addrlen:地址结构体大小

    3、返回值:
    成功:0
    失败:-1


    三、将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数

    1、头文件 #include <sys/types.h>
                    #include <sys/socket.h>

    2、接口声明 int listen(int socket, int backlog);
    参数:
    a、sockfd:待连接套接字
    b、最大同时连接请求个数

    3、返回值:
    成功:0,并将sockfd设置为监听套接字
    失败:-1

    四、等待对端连接请求

    1、头文件 #include <sys/types.h>
                     #include <sys/socket.h>

    2、接口声明 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    参数:
    a、sockfd:经过listen()之后的监听套接字
    b、addr:本来为(struct sockaddr_in)型的结构体,但是写进来的时候要强转成为(struct sockaddr *)型

    c、addrlen:为(struct sockaddr_in)结构体的大小


    3、返回值:
    成功:返回一个非负整数的文件描述符
    失败-1


    五、连接对端监听套接字

    1、头文件 #include <sys/types.h>
                     #include <sys/socket.h>

    2、接口声明 int connect(int sockfd, const struct sockaddr *addr,
    socklen_t addrlen);

    参数:
    a、sockfd:待连接的套接字
    b、addr:本来为(struct sockaddr_in)型的结构体,但是写进来的时候要强转成为(struct sockaddr *)型
    c、addrlen:为(struct sockaddr_in)结构体的大小

    3、返回值:
    成功:0
    失败:-1


    六、断开本端连接套接字

    1、头文件 #include <unistd.h>

    2、接口声明 int close(int fd);
    参数:
    a、fd:文件描述符

    3、返回值:
    成功:0
    失败:-1


    七、断开本端连接套接字

    1、头文件 #include <sys/types.h>
                    #include <sys/socket.h>

    2、接口声明 int shutdown(int sockfd, int how);
    参数:
    a、sockfd:accept()成功之后的已连接套接字(文件描述符)

    b、how:断开方式
    SHUT_RD
    Disables further receive operations. //关闭读端

    SHUT_WR
    Disables further send operations. //关闭写端

    SHUT_RDWR
    Disables further send and receive operations. //关闭读写端

    3、返回值:
    成功:0
    失败:-1


    八、将文本地址转化为二进制地址

    1、头文件 #include <arpa/inet.h>

    2、接口声明 int inet_pton(int af, const char *src, void *dst);
    参数:
    a、af:地址族:
    AF_INET:ipv4地址
    AF_INET6:ipv6地址

    b、src:指向“点分式”ipv4或ipv6地址的指针:例如:192.168.1.105

    c、dst:类型为(struct in_addr *)的指针

    3、返回值:
    成功:1
    失败:0代表地址与地址族不匹配,-1代表地址不合法

    九、将二进制地址转化为文本地址

    1、头文件 #include <arpa/inet.h>

    2、接口声明 const char *inet_ntop(int af, const void *src,
    char *dst, socklen_t size);

    参数:
    a、af:地址族:
    AF_INET:ipv4地址
    AF_INET6:ipv6地址

    b、src:指向“点分式”ipv4或ipv6地址的指针:例如:192.168.1.105

    c、dst:地址缓冲区指针

    d、size:地址缓冲区大小

    3、返回值:
    成功:returns a non-NULL pointer to dst.
    失败:NULL


    十、向TCP套接字发送数据

    1、头文件IS #include <sys/types.h>
                        #include <sys/socket.h>


    2、接口声明 ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    参数:
    a、sockfd:已连接的套接字

    b、buf:即将被发送的数据

    c、len:数据长度

    d、flags:发送标志(可以填0)
    MSG_EOR:当对端已关闭时,不产生SIGPIPE信号
    MSG_OOB :发送紧急(带外)数据,只针对TCP连接

    3、返回值:
    成功:已发送字节数
    失败:-1

    备注当flags为0时,send与write作用一样,所以TCP也可以用write发送数据

    十一、从TCP套接字接收数据

    1、头文件 #include <sys/types.h>
                     #include <sys/socket.h>

    2、接口声明 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    参数:
    a、sockfd:已连接套接字

    b、buf:存储数据缓冲区

    c、len:缓冲区大小

    d、flags:接收标志(可以填0)

    3、返回值:
    成功:已接收字节数
    失败:-1
    备注当flags为0时,recv与read作用一样,所以TCP也可以用read来接收数据


    十二、向UDP套接字发送数据

    1、头文件 #include <sys/types.h>
                    #include <sys/socket.h>

    2、接口声明 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
    const struct sockaddr *dest_addr, socklen_t addrlen);
    参数:
    a、sockfd:UDP(套接字) (SOCK_DGRAM :数据报套接字)

    b、buf:即将被发送的数据

    c、len:数据长度

    d、flags:发送标志:与send函数的flags一样

    e、dest_addr:对端网络地址

    f、addr_len:地址长度 (struct sockaddr_in 的大小)

    3、返回值:
    成功:已发送字节数
    失败:-1

    备注:
    当dest_addr为NULL,aaddrlen为0时,sendto与send作用一致


    十三、从UDP套接字接收数据

    1、头文件 #include <sys/types.h>
                    #include <sys/socket.h>

    2、接口声明 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
    struct sockaddr *src_addr, socklen_t *addrlen);

    参数:
    a、sockfd:UDP(套接字) (SOCK_DGRAM :数据报套接字)

    b、buf:存储数据缓冲区

    c、len:缓冲区大小

    d、flags:接收标志:与send函数的flags一样

    e、dest_addr:对端网络地址

    f、addr_len:地址长度 (struct sockaddr_in 的大小)

    3、返回值:
    成功:已接收字节数
    失败:-1


    十四、多路复用

    1、头文件 #include <sys/select.h>

    2、接口声明 int select(int nfds, fd_set *readfds, fd_set *writefds,
    fd_set *exceptfds, struct timeval *timeout);
    参数:
    a、nfds:所有正在监测的套接字的最大值加1

    b、readfds:读就绪文件描述符集合

    c、writefds:写就绪文件描述符集合

    d、execeptfds:异常就绪文件描述符集合

    e、timeout:超时控制

    3、返回值:
    成功:就绪文件描述符总数(当超过返回时为0)
    失败-1


    超时设置:
    The timeout
    The time structures involved are defined in <sys/time.h> and look like

    struct timeval {
    long tv_sec; /* seconds */ 秒
    long tv_usec; /* microseconds */ 微秒
    };

    and

    struct timespec {
    long tv_sec; /* seconds */
    long tv_nsec; /* nanoseconds */ 纳秒
    };


    文件描述符集合操作函数:
    void FD_CLR(int fd, fd_set *set);
    int FD_ISSET(int fd, fd_set *set);
    void FD_SET(int fd, fd_set *set);
    void FD_ZERO(fd_set *set);

     

    下面是简单的例子,服务器负责接收数据,客户端负责发送数据。

    ================================下面为TCP的代码=====================

    1、服务器:service.c

    #include <sys/types.h>          
    #include <sys/socket.h>
    #include <stdio.h>
    #include <linux/in.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define IP "192.168.1.104"   //这是我的虚拟机上的IP,读者要改成自己的IP
    #define PORT 50001     //端口号(可改)
    #define LISTEN_MAX 8   //最大同时接收连接请求个数
    #define LENGTH 100     //数组的大小
    
    int main(int argc,char *argv[])
    {
        int sockfd; 
        char buf[LENGTH];
        //1、创建TCP套接字(SOCK_STREAM为TCP),AF_INET为ipv4
        sockfd = socket(AF_INET,SOCK_STREAM,0);  
        if(sockfd == -1)
        {
            perror("socket");
            exit(1);
        }
        
        //2、设置端口号和IP
        struct sockaddr_in srvaddr,cliaddr;
        socklen_t len = sizeof(cliaddr);
        srvaddr.sin_family = AF_INET;    //ipv4
        srvaddr.sin_port = htons(PORT);  //端口号
        inet_pton(AF_INET,IP,&srvaddr.sin_addr); //将文本地址转化为二进制地址
        
        
        //3、绑定套接字与网络地址
        int ret = bind(sockfd,(struct sockaddr *)&srvaddr,len); 
        if(ret == -1)
        {
            perror("bind");
            exit(1);
        }
        
        //4、将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数4、
        int ret1 = listen(sockfd,LISTEN_MAX); 
        if(ret1 == -1)
        {
            perror("listen");
            exit(1);
        }
        
        //5、等待客户端端连接的请求,这是阻塞的
        int connfd = accept(sockfd,(struct sockaddr*)&cliaddr,&len); 
        if(connfd == -1)
        {
            perror("accept");
            exit(1);
        }
        
        
        while(1)
        {
            memset(buf,0,sizeof(buf));
            recv(connfd,buf,sizeof(buf),0); //读出客户端发送过来的数据,这里可以用read代替
            printf("from client:%s",buf);
            
            if(strncmp(buf,"quit",4) == 0)
            {
                break;
            }
        }
        
        close(connfd);
        close(sockfd);
    }

    2、客户端:client.c

    #include <sys/types.h>          
    #include <sys/socket.h>
    #include <stdio.h>
    #include <linux/in.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    #define IP "192.168.1.104"   //这是我的虚拟机上的IP,读者要改成自己的IP
    #define PORT 50001    //端口号(要跟服务器上的一致)
    #define LENGTH 100 //数组大小
    int main(int argc,char *argv[])
    {
        char buf[LENGTH];
        
        //1、创建TCP套接字(SOCK_STREAM为TCP),AF_INET为ipv4
        int sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(sockfd == -1)
        {
            perror("socket");
            exit(1);
        }
        
        
        //2、设置服务器的IP与端口号
        struct sockaddr_in srvaddr;
        socklen_t len = sizeof(srvaddr);
        srvaddr.sin_family = AF_INET;  //ipv4
        srvaddr.sin_port = htons(PORT);  //端口号
        inet_pton(AF_INET,IP,&srvaddr.sin_addr); //将文本地址转化为二进制地址
        
        
        //3、发送连接请求,这是阻塞的
        int ret = connect(sockfd,(struct sockaddr*)&srvaddr,len); 
        if(ret == -1)
        {
            perror("connect");
            exit(1);
        }
        
        while(1)
        {
            memset(buf,0,sizeof(buf));
            fgets(buf,sizeof(buf),stdin);
            send(sockfd,buf,strlen(buf),0); //向服务器发送数据,这里可以用write代替
            
           if(strncmp(buf,"quit",4) == 0)
           {
               break;
           }
        }
        
        close(sockfd);
        return 0;
    }


    ================================下面为UDP的代码=====================

    1、服务器:service.c

    #include <sys/types.h>          
    #include <sys/socket.h>
    #include <stdio.h>
    #include <linux/in.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    #define IP "192.168.1.104"   //这是我的虚拟机上的IP,读者要改成自己的IP
    #define PORT 50002 //端口号
    #define LENGTH 100 //数组大小
    
    
    int main(int argc,char *argv[])
    {
        // 1、创建UDP套接字 ,AF_INET为iPv4,SOCK_DGRAM为UDP
        int sockfd = socket(AF_INET,SOCK_DGRAM,0) ;
        if(sockfd == -1)
        {
            perror("socket");
            exit(1);
        }
        
       //2、设置端口号和IP
       struct sockaddr_in  srvaddr,cliaddr;
       socklen_t len = sizeof(cliaddr);
       srvaddr.sin_family = AF_INET;
       srvaddr.sin_port = PORT;
       inet_pton(AF_INET,IP,&srvaddr.sin_addr); //将文本地址转化为二进制地址
       
       //3、绑定套接字与网络地址
      int ret = bind(sockfd,(struct sockaddr*)&srvaddr,sizeof(srvaddr));
       if(ret == -1)
       {
           perror("bind");
           exit(1);
       }
       
       char buf[LENGTH];
       while(1)
       {
           memset(buf,0,sizeof(buf));
           recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len);
           printf("from client:%s",buf);
           if(strncmp(buf,"quit",4) == 0)
           {
               break;
           }
       }
       
       close(sockfd);
       return 0;
       
    }

    2、客户端:client.c

    #include <sys/types.h>          
    #include <sys/socket.h>
    #include <stdio.h>
    #include <linux/in.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    #define IP "192.168.1.104"   //这是我的虚拟机上的IP,读者要改成自己的IP
    #define PORT 50002     //端口号(要跟服务器上的一致)
    #define LENGTH 100 //数组大小
    
    int main(int argc,char *argv[])
    {
        //1、创建UDP套接字(SOCK_DGRAM为UDP),AF_INET为ipv4
        int sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(sockfd == -1)
        {
            perror("socket");
            exit(1);
        }
        
        //2、设置对方的IP与端口号
        struct sockaddr_in srvaddr;
        srvaddr.sin_family = AF_INET;
        srvaddr.sin_port = PORT;
        inet_pton(AF_INET,IP,&srvaddr.sin_addr);//将文本地址转化为二进制地址
        
        char buf[LENGTH];
        while(1)
        {
            memset(buf,0,sizeof(buf));
            fgets(buf,sizeof(buf),stdin);
            sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&srvaddr,sizeof(srvaddr));
            if(strncmp(buf,"quit",4) == 0)
            {
                break;
            }
        }
        
        close(sockfd);
    }
    鉴于本人才疏学浅,所以其中不免有遗漏或者错误,恳请各位博友批评指正。
  • 相关阅读:
    1.写一个Java程序,把一个英语句子中的单词次序颠倒后输出。例如输入“how are you”,输出“you are how”; 2.编写单元测试进行测试; 3.用ElcEmma查看代码覆盖率,要求覆盖率达到100%
    1. 写一个Java程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示。(单词之间用空格隔开,如“Hello World My First Unit Test”); 2. 编写单元测试进行测试; 3. 用ElcEmma查看代码覆盖率,要求覆盖率达到100%。
    个人简介
    第六次作业
    第五次作业
    软件测试第二次作业(2)
    软件测试第二次作业(1)
    个人简介
    闽江学院2015-2016学年下学期《软件测试》课程-第六次博客作业
    闽江学院2015-2016学年下学期《软件测试》课程-第二次作业(个人作业)
  • 原文地址:https://www.cnblogs.com/wurenzhong/p/7434754.html
Copyright © 2020-2023  润新知