• Linux Socket编程的一些总结


    最近写了一些Linux下网络编程的一些程序,做几点总结吧。

    先给出客户端后服务器的一些Socket初始化的代码,以后可以直接拿来调用。

    客户端Socket初始化代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <time.h>
    #include <strings.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <sys/time.h>
    #define IP "192.168.1.111"
    #define PORT 12346
    int init_socket()
    {
       struct sockaddr_in server_addr;
       int err;
       int client_socket;
       client_socket=socket(AF_INET,SOCK_STREAM,0);
       if(client_socket<0)
       {
          printf("socket erro\n");
          return ;
       }
       //设置服务器端的地址,端口等
      server_addr.sin_family=AF_INET;
      server_addr.sin_addr.s_addr=inet_addr(IP);//字符串类型转IP类型
      server_addr.sin_port=htons(PORT);
      bzero(&(server_addr.sin_zero),8);
      connect(client_socket,(struct sockaddr *)&server_addr,sizeof(struct sockaddr));//连接服务器
      return client_socket;
    }

    直接调用上面的函数返回一个套接字的文件描述符,利用它便可以和服务器进行通信。

    下面给出服务器socket初始化的代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <errno.h>
    #include <openssl/des.h>
    #include <sys/time.h>
    #include <fcntl.h>
    #define PORT 12346
    #define BACKLOG 20
    int init_server_socket()
    {
       int server_socket,server_client_socket;
       struct sockaddr_in server_addr;
    
       int err;
       //创建套接字
       server_socket=socket(AF_INET,SOCK_STREAM,0);
       if(server_socket<0)
       {
          printf("socket error\n");
          return -1;
       }
       //设置服务器端的地址,端口等
       server_addr.sin_family = AF_INET;
       server_addr.sin_port = htons(PORT);
       server_addr.sin_addr.s_addr = htons(INADDR_ANY);
       bzero(&(server_addr.sin_zero), 8);
       //将创建的套接字绑定到服务器端
       err = bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
       if(err<0)
       {
          printf("bind error\n");
          return -1;
       }
       //监听套接字
       err=listen(server_socket,BACKLOG);
       if(err<0)
       {
          printf("listen error\n");
          return -1;
       }
       return server_socket;
    }

    上面的初始化函数返回了一个套接字文件描述符,我们在服务器程序中,可以写一个循环,当有客户端连接请求的时候,服务器就建立一个线程和服务器进行通信。代码如下所示:

    while(1)
        {
            int addrlen=sizeof(struct sockaddr);
            struct sockaddr_in client_addr;
            //如果调用成功,将返回一个新的套接字与客户端通信
            server_client_socket=accept(server_socket,(struct sockaddr*)&client_addr,&addrlen);
            //下面两行是将这个socket连接设置成非阻塞模式
            // int flags = fcntl(server_client_socket, F_GETFL, 0);
            // fcntl(server_client_socket, F_SETFL, flags | O_NONBLOCK);
            printf("%s has connected success\n",inet_ntoa(client_addr.sin_addr));
            //在这里写创建线程程序
            。。。。。。
            usleep(100);
        }
    

    要点总结:

    1、在服务器端程序要判断recv()函数的返回值,如果对方发送的数据比较的则需采用循环接收的方法,比如对方一次发了4096字节的数据,一次rrecv()可能接收不了,则需要多次接收,直到接收的总数等于4096字节,看下面的代码你就会明白

    #define MAXBUFFER_SIZE 4096
    int total_reieved =0;
    char recvbuffer[MAXBUFFER_SIZE];
    while(1)
           {
              if(MAXBUFFER_SIZE==total_reieved)
                  break;
              int size=recv(server_client_socket,recvbuffer+total_reieved,MAXBUFFER_SIZE-total_reieved,0);
              total_reieved+=size;
          }

    2、如果发送方的程序关闭了,在接收方就会不断recv()并返回0,则我们就要关闭这个连接,防止接收方陷入死循环

    3、拔网线拔掉重新插上,socket可以自动恢复连接

    4、默认的连接时阻塞模式的,如果要将套接字通信设置成非阻塞模式我们可以参考下面的代码(对套接字文件描述符设置),非阻塞模式下如果读不到数据则返回-1,网络断开也是返回-1

    int flags = fcntl(server_client_socket, F_GETFL, 0);
    fcntl(server_client_socket, F_SETFL, flags | O_NONBLOCK);

    5、假如客户端程序一直发送数据,服务器程序一直接受数据,这时服务器程序关闭,则客户端程序也会关闭,这时因为服务器close一个连接时,若客户端接这发数据,系统会产生一个SIGPIPE信号,告诉进程连接已经断开了,而处理这个信号的默认动作是使进程退出,如果不想进程退出,可以把SIGPIPE设为SIG_IGN。调用函数signal(SIGPIPE,SIG_IGN);

    大概就总结了这几点,欢迎批评和指正。



  • 相关阅读:
    更快的datetime string to python datetime转换模块 ciso8601
    华为新员工入职培训计划曝光!你留不住员工的原因就在这! zz
    在vmware中安装macos系统 vm12 osx10.11 or higher
    vmware for linux (centos65) 卸载相关
    第八章多态
    第七章 复用类
    第六章 访问权限控制
    Think in Java 第四 五 章
    Think in Java 第三章操作符
    Thank in Java
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3129883.html
Copyright © 2020-2023  润新知