美文网首页
Linux下socket编程

Linux下socket编程

作者: 吴金君 | 来源:发表于2019-05-03 15:47 被阅读0次

    套接字地址结构

    \include<netinet/in.h>
    struct in_addr
    {
      in_addr_t s_addr; 
    };
    struct sockaddr_in
    {
      uint8_t  sin_len;
      sa_family_t sin_family;
      in_port_t sin_port;
      struct in_addr sin_addr[8];
    }
    

    TCP

    image

    总结函数用法

    socket函数
    #include <sys/socket.h>
    socket(int family,int type, int protocol)
    参数:family 指明协议族,type 指数据类型,protocol 指协议
    返回值:成功为非负描述符,若出错则为-1

    family
    type
    protocol

    bind函数
    #include <sys/socket.h>
    int bind(int sockfd,const struct sockaddr * myaddr, socklen_t addrlen)
    参数:sockfd指socket套接字描述符,myaddr指向需要绑定的网络地址结构,addrlen是网络地址结构的长度
    返回值:成功返回0,出错返回-1

    listen函数
    #include <sys/socket.h>
    int listen(int sockfd,int backlog)
    输入参数:sockfd是socket套接字描述符,backlog可以理解为连接队列容量大小(已连接+未连接)
    返回值:成功返回0,出错返回-1

    accept函数
    #include <sys/socket.h>
    int accept(int sockfd, const struct sockaddr * clientaddr, socklen_t addrlen)
    输入参数:sockfd是socket套接字描述符,clientaddr指向客户的网络地址结构,addrlen是网络地址结构的大小。
    返回值:成功返回非负描述符,出错返回-1

    connect函数
    #include <sys/socket.h>
    int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen)
    TCP客户端用connect函数发起与服务器的连接
    参数:sockfd指socket函数返回的套接字描述符,*servaddr是指向套接字结构的指针,addrlen是套接字结构的大小
    返回值:成功返回0,出错返回-1
    sockfd是客户端套接字描述符
    servaddr套接字结构必须含有服务器IP和端口

    send函数
    ssize_t send(int sockfd, const char *buf, size_t len, int flags );
    参数:sockfd套接字(已连接套接字),buf是发送缓存区,len是缓存区长度,
    返回值:copy的字节数

    recv函数
    ssize_t recv(int sockfd, char *buf, size_t len, int flags)
    参数:参数:sockfd套接字(已连接套接字),buf是接收缓存区,len是缓存区长度。
    返回值:copy的字节数

    close函数
    close(int sockfd)将套接字标记为关闭
    参数:sockfd指socket函数返回的套接字描述符

    read函数
    #include<unistd.h>
    sszie_t read(int fd, void* buf, size_t nbyte)
    参数:fd文件描述符,nbyte
    返回值:读到的字节数;若到文件尾部,返回0;若出错返回-1

    write函数
    #include<unistd.h>
    sszie_t write(int fd, void* buf, size_t nbyte)
    参数:fd文件描述符,buf待写入的缓存
    返回值:若成功,返回写入的字节数;若出错返回-1

    socket(), connect(), accept()三个函数之间的关系
    1. socket函数创建的监听套接字(listening socket)描述符,随后用作bind和listen的第一个参数
    2. accept函数返回值为已连接套接字(connected socket)描述符
    3. 一个服务器通常仅仅创建一个监听套接字,在服务器生命周期中一直存在;
    4. 内核为每个已连接客户端创建一个已连接套接字

    服务端处理流程:

    1. 调用socket函数,建立套接字描述符
    2. 创建网络地址数据结构,指定要监听的IP和PORT
    3. 调用bind函数,将套接字描述符合万罗地址数据结构绑定
    4. 调用listen函数,将套接字描述符转为监听套接字,表示该描述符是用于从指定地址和端口接收连接的
    5. 阻塞等待,调用accept函数来获取连接
    6. 得到连接后使用read和write函数往描述符中读写数据
    7. 完成后调用close关闭套接字描述符

    客户端处理流程

    1. 调用socket函数,创建套接字描述符
    2. 创建网络地址结构,指定要连接的服务端IP和PORT
    3. 调用connect函数连接服务器
    4. 连接成功后调用read和write函数读写数据
    5. 完成后调用close关闭描述符

    server代码

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/shm.h>
    #include <iostream>
    #define PORT 7000
    #define QUEUE 20
    
    int main()
    {
        fd_set rfds;
        struct timeval tv;
        int retval,maxfd;
        //创建socket
        int listener =socket(AF_INET,SOCK_STREAM,0);//ipv4,stream data,TCP
        struct sockaddr_in server_sockaddr;
        server_sockaddr.sin_family = AF_INET;
        server_sockaddr.sin_port = htons(PORT);
        server_sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        //bind
        if(bind(listener,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))<0);
        {
            perror("bind error");
            exit(1);
        }
        //listen
        if(listen(listener,QUEUE)<0)
        {
            perror("listen");
            exit(1);
        }
        //connect
        struct sockaddr_in client_addr;
        socklen_t length= sizeof(client_addr);
        int conn=accept(listener,(struct sockaddr *)&client_addr,&length);
        if(conn<0)
        {
            perror("connect");
            exit(1);
        }
        while(1)
        {
            /*把可读文件描述符的集合清空*/
            FD_ZERO(&rfds);
            /*把标准输入的文件描述符加入到集合中*/
            FD_SET(0, &rfds);
            maxfd = 0;
            /*把当前连接的文件描述符加入到集合中*/
            FD_SET(conn, &rfds);
            /*找出文件描述符集合中最大的文件描述符*/
            if(maxfd<conn)
            {
                maxfd=conn;
            }
            /*设置超时时间*/
            tv.tv_sec = 5;
            tv.tv_usec = 0;
            retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
            if(retval == -1){
                printf("select出错,客户端程序退出\n");
                break;
            }else if(retval == 0){
                printf("服务端没有任何输入信息,并且客户端也没有信息到来,waiting...\n");
                continue;
            }else{
                /*客户端发来了消息*/
                if(FD_ISSET(conn,&rfds))
                {
                    char buffer[1024];
                    memset(buffer, 0,sizeof(buffer));
                    int len = recv(conn,buffer,sizeof(buffer),0);
                    if(strcmp(buffer,"exit\n")==0)break;
                    printf("%s",buffer);
                    //send(conn,buffer,len,0);
                    
                }
                /*用户输入信息了,开始处理信息并发送*/
                if(FD_ISSET(0,&rfds))
                {
                    char buf[1024];
                    fgets(buf,sizeof(buf),stdin);
                    send(conn,buf,sizeof(buf),0);
                }
            }
        }
        close(conn);
        close(listener);
        return 0;
    }
    

    client代码

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/shm.h>
    
    #define MYPORT  7000
    #define BUFFER_SIZE 1024
    
    int main()
    {
        int sock_client;
        fd_set rfds;
        struct timeval tv;
        int retval, maxfd;
        
        //定义 sockfd
        sock_client = socket(AF_INET,SOCK_STREAM,0);
        //定义 socketaddr_in
        struct sockaddr_in serveraddr;
        memset(&serveraddr,0,sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(MYPORT);
        serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");//server ip
        
        while(connect(sock_client,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0)
        {
            perror("connect");
            exit(1);
        }
        
        while(1)
        {
            /*把可读文件描述符的集合清空*/
            FD_ZERO(&rfds);
            /*把标准输入的文件描述符加入到集合中*/
            FD_SET(0, &rfds);
            maxfd = 0;
            /*把当前连接的文件描述符加入到集合中*/
            FD_SET(sock_client, &rfds);
            /*找出文件描述符集合中最大的文件描述符*/
            if(maxfd < sock_client)
                maxfd = sock_client;
            /*设置超时时间*/
            tv.tv_sec = 5;
            tv.tv_usec = 0;
            /*等待聊天*/
            retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
            if(retval == -1){
                printf("select出错,客户端程序退出\n");
                break;
            }else if(retval == 0){
                printf("客户端没有任何输入信息,并且服务器也没有信息到来,waiting...\n");
                continue;
            }else{
                /*服务器发来了消息*/
                if(FD_ISSET(sock_client,&rfds))
                {
                    char recvbuf[BUFFER_SIZE];
                    int len;
                    len = recv(sock_client,recvbuf,sizeof(recvbuf),0);
                    printf("%s",recvbuf);
                    memset(recvbuf,0,sizeof(recvbuf));
                }
                if(FD_ISSET(0,&rfds))
                {
                    char sendbuf[BUFFER_SIZE];
                    fgets(sendbuf,sizeof(sendbuf),stdin);
                    send(sock_client,sendbuf,strlen(sendbuf),0);
                    memset(sendbuf,0,sizeof(sendbuf));
                }
            }
        }
        close(sock_client);
        return 0;
    }
    

    https://blog.csdn.net/chenchukun/article/details/78991215

    相关文章

      网友评论

          本文标题:Linux下socket编程

          本文链接:https://www.haomeiwen.com/subject/pdtxoftx.html