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);

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



原文地址:https://www.cnblogs.com/dyllove98/p/3129883.html