zoukankan      html  css  js  c++  java
  • linux网络编程

    套接字概述

    在Linux中,一切都是文件. Linux 中的网络编程通过socket接口进行,   socket是一种特殊的I/0接口, 也是一种文件描述符. 常用的进程之间通信.   下图是使用TCP协议的通信过程 :

    三次握手建立连接

    四次挥手断开连接

     

    这里通过实现两个例子了解一些常用API的用法, 不废话, 直接上代码.

    1.回声客户端

    服务端代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<pthread.h>
    #include<unistd.h>
    #include<errno.h>
    #include<netdb.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<sys/types.h>
    
    #define            PORT                4321        //端口号
    #define            BUFFER_SIZE            1024        //缓冲区大小    
    #define            MAX_QUE_CONN_NM        5            //最大请求队列
    
    /* 处理客户端请求 */
    void *conn_hand(void *arg){
        
        int client_fd = *(int *)arg;
        int recvbytes, sendbytes;
        char buf_recv[BUFFER_SIZE] = {0}, buf_send[BUFFER_SIZE];
    
        while(1){
        
            /* 调用recv()函数, 接受客户端请求. 从缓冲区中读取. */
            if((recvbytes = recv(client_fd, buf_recv, BUFFER_SIZE, 0)) == -1){
                perror("recv");
                break;
            }
            printf("receive from client: %s
    ", buf_recv);
    
            /* 退出 */
            if(strcmp(buf_recv, "quit") == 0) break;
    
            /* 向客户端发送数据  这里只是写入缓冲区, 由TCP协议发送至网络中*/
            if(send(client_fd, buf_recv, recvbytes, 0) == -1){
                perror("send");
                break;
            }
            memset(buf_recv, 0, BUFFER_SIZE);
    
        }
        printf("terminating current connect...
    ");
        close(client_fd);
        pthread_exit(NULL);
    }
    
    int main(void){
    
        struct sockaddr_in server_sockaddr, client_sockaddr;
        int sin_size;
        int sockfd, client_fd;
    
        /* 建立socket连接 */
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(1);
        }
        printf("socket id=%d
    ", sockfd);
        
        /* 设置sockaddr_in 结构体参数 */
        server_sockaddr.sin_family = AF_INET;
        server_sockaddr.sin_port = htons(PORT);
        server_sockaddr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(server_sockaddr.sin_zero),8) ;
    
        /* 允许重复本地址绑定套接字 */
        int i = 1;
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
    
        /* 绑定函数bind() */
        if(bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1){
            perror("bind");
            exit(1);
        }
        printf("bind success!
    ");
        
        /* 调用listen函数监听, 创建未处理请求队列 */
        if(listen(sockfd, MAX_QUE_CONN_NM) == -1){
            perror("listen");
            exit(1);
        }
        printf("listening port:%d ...
    ", PORT);
       
        sin_size = sizeof(client_sockaddr);
        /* 循环接收客户端请求 */
        while(1){
            pthread_t tid;
    
            client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size);
            
            /* 创建新线程处理客户端请求*/
            if(pthread_create(&tid, NULL, conn_hand, &client_fd) == -1){
                perror("pthread_create");
                break;
            }
        }
        close(sockfd);
        exit(0);
    }
    View Code  

    客户端代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    #include<netdb.h>
    #include<errno.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<sys/types.h>
    
    #define                PORT                4321            //端口
    #define                BUFFER_SIZE            1024            //缓冲区大小
    
    int main(int argc, char *argv[]){
    
        int sockfd, sendbytes, recvbytes;
        char buf_recv[BUFFER_SIZE], buf_send[BUFFER_SIZE];
        struct hostent *host;
        struct sockaddr_in serv_addr;
    
        if(argc != 2){
            fprintf(stderr, "usage: ./client <ip address>
    ");
            exit(1);
        }
    
        /* 地址解析函数 */
        if((host = gethostbyname(argv[1])) == NULL){
            perror("gethostbyname");
            exit(1);
        }
        
        /* 设置sockaddr_in结构体参数 */
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(PORT);
        serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
        bzero(&(serv_addr.sin_zero), 8);
        
        /* 创建socket */
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(1);
        }
    
        /*发起连接 */
        if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
            perror("connect");
            exit(1);
        }
    
        //循环发送请求
        while(1){
            /* 发送消息 */
            printf("sent to server:");
            scanf("%s", buf_send);
    
            if((sendbytes = send(sockfd, buf_send, strlen(buf_send), 0)) == -1){
                perror("send");
                exit(1);
            }
    
            if(strcmp(buf_send, "quit") == 0) break;
    
            /* 读取回送消息 */
            if((recvbytes = recv(sockfd, buf_recv, BUFFER_SIZE, 0)) > 0){
                printf("receive from server : %s
    ", buf_recv);
            }
            
        }
    
        close(sockfd);
        exit(0);
    }
    View Code

    编译运行

    服务端
    $ gcc server.c -o server -lpthread
    $ ./server
    socket id=3
    bind success!
    listening port:4321 ...
    receive from client: 
    客户端
    $ gcc client.c -o client -lpthread $ ./client 127.0.0.1 sent to server:1 receive from server : 1 sent to server:quit

    2.文件传输

    服务端代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include<netdb.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<sys/types.h>
    
    #define            PORT                4321        //端口号
    #define            BUFFER_SIZE            1024        //缓冲区大小    
    #define            MAX_QUE_CONN_NM        5            //最大请求队列
    
    int main(void){
    
        struct sockaddr_in server_sockaddr, client_sockaddr;
        int sin_size, recvbytes;
        int sockfd, client_fd;
        FILE *fp = fopen("file.txt", "rb");
        if(fp ==NULL){
            perror("file");
            exit(1);
        }
    
    
        /* 建立socket连接 */
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(1);
        }
        printf("socket id=%d
    ", sockfd);
        
        /* 设置sockaddr_in 结构体参数 */
        server_sockaddr.sin_family = AF_INET;
        server_sockaddr.sin_port = htons(PORT);
        server_sockaddr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(server_sockaddr.sin_zero),8) ;
        
        int i = 1;    /* 允许重复使用本地地址与套接字绑定 */
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
    
        /* 绑定函数bind() */
        if(bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1){
            perror("bind");
            exit(1);
        }
        printf("bind success!
    ");
        
        /* 调用listen函数监听, 创建未处理请求队列 */
        if(listen(sockfd, MAX_QUE_CONN_NM) == -1){
            perror("listen");
            exit(1);
        }
        printf("listening port:%d ...
    ", PORT);
    
        /* 发送数据 */
        sin_size = sizeof(client_sockaddr);
        char buf_send[BUFFER_SIZE] = {0};
        if((client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size)) == -1){
                perror("accept");
                exit(1);
        }
        /* 向客户端发送数据  这里只是写入缓冲区, 由TCP协议发送至网络中*/
        int count;
        while((count = fread(buf_send, 1, BUFFER_SIZE, fp)) > 0){
            if(send(client_fd, buf_send, count, 0) == -1){
                perror("send");
                exit(1);
            }
        }
    
        /* 文件读取完毕, 断开输入流, 发送FIN数据包 */
        shutdown(client_fd, 2);
        /* 阻塞, 一旦客户端接收完毕,server收到FIN包, 继续向下执行  */
        recv(client_fd, buf_send, BUFFER_SIZE, 0);
    
        fclose(fp);
        close(client_fd);
        close(sockfd);
        exit(0);
    }
    View Code

    客户端代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    #include<netdb.h>
    #include<errno.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<sys/types.h>
    
    #define                PORT                4321            //端口
    #define                BUFFER_SIZE            1024            //缓冲区大小
    
    int main(int argc, char *argv[]){
    
        int sockfd, sendbytes, recvbytes;
        struct hostent *host;
        struct sockaddr_in serv_addr;
        FILE *fp;
        fp = fopen("file_download.txt", "wb");
    
        if(fp ==NULL){
            perror("file");
            exit(1);
        }
    
        if(argc < 2){
            fprintf(stderr, "USAGE: ./client Hostname(or ip address) Text
    ");
            exit(1);
        }
    
    
    
        /* 地址解析函数 */
        if((host = gethostbyname(argv[1])) == NULL){
            herror("gethostbyname");
            exit(1);
        }
        
        /* 设置sockaddr_in结构体参数 */
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(PORT);
        serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
        bzero(&(serv_addr.sin_zero), 8);
        
        /* 创建socket */
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(1);
        }
    
        
        /*发起连接 */
        if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
            perror("connect");
            exit(1);
        }
    
        /* 接收文件 */
        char buf_recv[BUFFER_SIZE] = {0};
        while((recvbytes = recv(sockfd, buf_recv, BUFFER_SIZE, 0)) > 0){
            fwrite(buf_recv, recvbytes, 1, fp);
        }
    
        printf("文件接收完毕
    ");
    
        fclose(fp);
        close(sockfd);
        exit(0);
    }
    View Code
  • 相关阅读:
    浅谈函数式编程
    理解Spark SQL(三)—— Spark SQL程序举例
    理解Spark SQL(二)—— SQLContext和HiveContext
    理解Spark SQL(一)—— CLI和ThriftServer
    理解Spark运行模式(三)(STANDALONE和Local)
    理解Spark运行模式(二)(Yarn Cluster)
    理解Spark运行模式(一)(Yarn Client)
    Java操作Excel:POI和EasyExcel
    MyBatis-Plus入门,看这一篇就足够了
    50道SQL面试题
  • 原文地址:https://www.cnblogs.com/tanxing/p/6784696.html
Copyright © 2011-2022 走看看