socket非阻塞型客户端与服务器实现

socket非阻塞客户端

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
//客户端非阻塞
typedef struct MySocketInfo{
    int socketCon;
    unsigned long ipaddr;
    unsigned short port;
}_MySocketInfo;
 
void *fun_thrReceiveHandler(void *socketCon);

 
int main()
{
    printf("开始socket\n");

    int socketCon = socket(AF_INET, SOCK_STREAM, 0);  
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(struct sockaddr_in));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    server_addr.sin_port=htons(1000);
    int flags =fcntl(socketCon,F_GETFL,0); //得到套接字描述符标志位
    if(flags<0)
    {
       printf("获取套接字描述符标志位失败\n");
       exit(-1);
    }
    else 
   {
      printf("得到套接字描述符标志位flags=%d\n",flags);
   }   
 //  flags=0;
//  int flagst=0;
   int flagst= fcntl(socketCon,F_SETFL,flags|O_NONBLOCK);//更改套接字描述符标志位
   if(flagst<0)
   {
     printf("更改套接字描述符失败\n");
     printf("flagst=%d",flagst);
     
 //   exit(-1);
   }
  else 
   {


      printf("更改套接字描述符标志成功flagst=%d\n",flagst);
     
   }
 //  struct timeval svTimeout;
  // svTimeout.tv_sec=5;
  // svTimeout.tv_usec=0;
  // int setsocktmp1=setsockopt(socketCon, SOL_SOCKET, SO_SNDTIMEO, (char *)&svTimeout, sizeof(struct timeval));
 //  int setsocktmp2= setsockopt(socketCon, SOL_SOCKET, SO_RCVTIMEO, (char *)&svTimeout, sizeof(struct timeval));
 
    int res_con = connect(socketCon,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr));
     if( res_con==0)
  {

      printf("连接的套接字res_con=%d\n",res_con);
      sleep(10);
  }

        
  
   else if((res_con<0)&&(errno!= EINPROGRESS))
  {
      printf("连接建立失败\n");
      printf("errno=%d",errno);
      printf("error:%s\n",strerror(errno));
  }

  else  if((res_con<0)&&(errno== EINPROGRESS))
  {
      printf("连接已建立但连接未成功\n");
      printf("errno=%d",errno);
      printf("error:%s\n",strerror(errno));
  
  
      fd_set writeset;//申明一个集合来保存要检测的套接字
      FD_ZERO(&writeset);//集合清零
      FD_SET(socketCon,&writeset);//要检测的套接字放在集合中
      
      struct timeval stTimeout;
      stTimeout.tv_sec=1;
      stTimeout.tv_usec=0;
     //   int res=-1;
     int res =select(socketCon+1,NULL,&writeset,NULL,&stTimeout);
   if(res<0)
   {
      printf("select出错\n");
      printf("errno=%d",errno);
      printf("error:%s\n",strerror(errno));

   }
   else if(res>0)
   {
      printf("时间未到被监控套接字状态发生改变\n");
      printf("res=%d\n",res);
      printf("errno=%d",errno);
      printf("error:%s\n",strerror(errno));
      if(FD_ISSET(socketCon,&writeset))
   {
    int error=0;
   socklen_t len =sizeof(error);
   if(getsockopt(socketCon,SOL_SOCKET,SO_ERROR ,&error ,&len)==-1)
    {
        printf("建立连接失败\n");
        printf("errno=%d",errno);
        printf("error:%s\n",strerror(errno));

    }
    else //成功返回零
    {
       printf("建立连接成功\n");
       printf("errno=%d",errno);
       printf("error:%s\n",strerror(errno));
    }
   }

   }
   else
   {
     printf("超时\n");
     printf("errno=%d",errno);
     printf("error:%s\n",strerror(errno));
   }
  }    
    pthread_t thrReceive;
    pthread_create(&thrReceive,NULL,fun_thrReceiveHandler,&socketCon);
    pthread_detach(thrReceive);
 while(1)
{  
        char userStr[300] = {'0'};
        scanf("%s",userStr);
        if(strcmp(userStr,"q") == 0)
        {
            printf("退出!\n");
            
        }
        // 发送消息
       
        int sendMsg_len = send(socketCon,userStr,300,0);
        if(sendMsg_len > 0)
       {
            printf("发送成功,服务端套接字:%d\n",socketCon);
        }else
       {
            printf("发送失败\n");
        }
 
   
 } 
    close(socketCon);

    return 0;
}
 
void *fun_thrReceiveHandler(void *socketCon)
{
   pthread_detach(pthread_self());//子线程自己分离自己线程
    while(1)
{
        char buffer[30];
        int _socketCon = *((int *)socketCon);
        int buffer_length = recv(_socketCon,buffer,300,MSG_DONTWAIT);
        if(buffer_length == 0)
        {
            printf("服务器端异常关闭\n");
            printf("errno=%d",errno);
            printf("error:%s\n",strerror(errno));
        }
        else if(buffer_length < 0)
        {
            printf("接受服务器数据失败\n");
            printf("errno=%d",errno);
            printf("error:%s\n",strerror(errno));

        }
       else 
       { 
         printf("接受到数据\n");
        // printf("buffer_length=%d \n",buffer_length);
         printf("errno=%d",errno);
         printf("error:%s\n",strerror(errno));
         buffer[buffer_length] = '\0';
          printf("服务器说:%s\n",buffer);
         memset(&buffer,0,sizeof(buffer));

       } 
        
        printf("进入非阻塞测试\n");
        
    sleep(1);  
    
 }   
    return NULL;
}

非阻塞型服务器

#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
//服务器端非阻塞
 
void *fun_thrReceiveHandler(void *socketInfo);
void *fun_thrAcceptHandler(void *socketListen);
//void *fun_id(void*on);
void setsocketunlock(int sock);
void fun_socket(); 
typedef struct MySocketInfo
{
    int socketCon;
    char *ipaddr;
    uint16_t port;
}_MySocketInfo;
 
// 客户端数组
struct MySocketInfo arrConSocket[10];
int conClientCount = 0;
 
// 接受客户端线程列表
pthread_t arrThrReceiveClient[10];
int thrReceiveClientCount = 0;
 
int main()
{
    
    int on=1;
    printf("开始socket\n");
//创建套接字
    
    int socketListen = socket(AF_INET, SOCK_STREAM, 0);
// printf("socketListen= %d\n" ,socketListen);
    if(socketListen < 0)
    {
        printf("创建失败\n");
        exit(-1);
    }
   else
    {
        printf("创建套接字成功\n");
    }
//通讯准备    
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(struct sockaddr_in));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    server_addr.sin_port=htons(2000); 
    
    int temp=1;
    int socketset3= setsockopt(socketListen, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp));
  if(socketset3<0)
  {
     perror("setsockopt");
     exit(-1);

  }

//本地地址与套接口捆绑
    if(bind(socketListen, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) != 0)
    {
        perror("绑定本地ip地址、端口号失败\n");
        exit(-1);
    }
    else
    {
        printf("绑定本地ip地址,端口号成功\n");
    }
 // 将套接字设为监听模式,等待队列最大长度为10
    if(listen(socketListen, 10) != 0){
        printf("开启监听失败\n");
        exit(-1);
    }
    else
     {
        printf("开启监听成功\n");
    }


    pthread_t thrAccept;  
    pthread_create(&thrAccept,NULL,fun_thrAcceptHandler,&socketListen);
    pthread_detach(thrAccept );//子线程与父线程分离开
 
while(1)
{
       
        printf("当前有接受数据线程多少个:%d\n",thrReceiveClientCount);
 
 //向客户端发送数据      
        char userStr[30] = {'0'};
        scanf("%s",userStr);
// 退出
        if(strcmp(userStr,"q") == 0)
        {
            printf("用户选择退出!\n");
            break;
        }

        if(conClientCount <= 0)
        {
            printf("没有客户端连接\n");
        }
        else
       {

    
            int i;
            for(i=0; i<conClientCount; i++)
              {
          //把输入内容写入发送客户端的数组中
                int sendMsg_len = send(arrConSocket[i].socketCon,userStr,300,0);
          //  printf("发送客户端的数据最大字节数:%d\n", sendMsg_len);
                if(sendMsg_len > 0)
               {
                    printf("向%s:%d发送成功\n",arrConSocket[i].ipaddr,arrConSocket[i].port);
                }
                else
                {
                    printf("向%s:%d发送失败\n",arrConSocket[i].ipaddr,arrConSocket[i].port);
                }
            }
        }
 
        sleep(0.5);
 }
 
    
    return 0;
}
//将套接字设置为非阻塞
void setsocketunlock(int sock)
{
   int flags=fcntl(sock,F_GETFL,0);
     if(flags<0)
 {
    printf("获取套接字描述符标志位失败\n");
   
}
   int flagst=fcntl(sock,F_SETFL,flags|O_NONBLOCK);
   if(flagst<0)
   {
     printf("更改套接字描述符失败flagst=%d\n",flagst);
   }
  else
 {

    printf("更改套接字描述符成功flagst=%d\n",flagst);

}
}
void *fun_thrAcceptHandler(void *socketListen)
 {
     
    while(1)
{
        int sockaddr_in_size = sizeof(struct sockaddr_in);
        struct sockaddr_in client_addr;
        bzero(&client_addr,sizeof(struct sockaddr_in));
        int _socketListen = *((int *)socketListen);
        printf("_socketListen=%d\n",_socketListen);
 
        //创建一个与客户端连接的套接字
    //    int socketCon = accept4(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size),SOCK_NONBLOCK);
  //  int socketCon = accept(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size));
         
       setsocketunlock(_socketListen);
  
        int socketCon = accept(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size));
       if(socketCon<0)
        {
           if(errno==EAGAIN)
          {
            printf("接受连接请求已经建立但未成功\n");
          }
           else if(errno!=EAGAIN)
          {
            printf("接受连接请求建立失败\n");
          }
        }
        fd_set writeset;
        FD_ZERO(&writeset);         
        FD_SET(socketCon,&writeset);
        struct timeval stTimeout;
        stTimeout.tv_sec=5;
        stTimeout.tv_usec=0;
        int res =select(socketCon+1,NULL,&writeset,NULL,&stTimeout);
        
        if(res>0)
      {
          printf("时间未到被监控套接字状态发生改变\n");
          printf("res=%d\n",res);
          printf("errno=%d",errno);
          printf("error:%s\n",strerror(errno));
        if(FD_ISSET(socketCon,&writeset))
      {
          int error=0;
          socklen_t len =sizeof(error);

          if(getsockopt(socketCon,SOL_SOCKET,SO_ERROR ,&error ,&len)==-1)
        {
            printf("连接失败\n");
            printf("errno=%d",errno);
            printf("error:%s\n",strerror(errno));
 
         }
         else //成功返回零
        {
           printf("连接成功\n");
          printf("连接的客户端套接字socketCon=%d\n",socketCon);
          printf("errno=%d",errno);
          printf("error:%s\n",strerror(errno));
         }

       }
     }
       else if(res<0)
     {    
            printf("select出错\n");
            printf("errno=%d",errno);
            printf("error:%s\n",strerror(errno));
           //错误类型为非法参数
      }
       else 
     {
           printf("超时,被监控的套接字文件不可写\n");
           printf("errno=%d",errno);
           printf("error:%s\n",strerror(errno));
           
      }

       _MySocketInfo socketInfo;
       socketInfo.socketCon = socketCon;
       socketInfo.ipaddr = inet_ntoa(client_addr.sin_addr);
        socketInfo.port = client_addr.sin_port;
       
       arrConSocket[conClientCount] = socketInfo;
       pthread_t thrReceive = 0;
        pthread_create(&thrReceive,NULL,fun_thrReceiveHandler,&socketInfo);
        pthread_detach(thrReceive);
        arrThrReceiveClient[thrReceiveClientCount] = thrReceive;
        thrReceiveClientCount++;
        conClientCount++;

        sleep(0.5);
    
 }
          
          sleep(2);

}
 //接收客户端发来的数据
void *fun_thrReceiveHandler(void *socketInfo)
{
	char buffer[30];
	int buffer_length;
	_MySocketInfo _socketInfo = *((_MySocketInfo *)socketInfo);

 //         setsocketunlock(_socketInfo.socketCon);


    while(1)
 {
       
        	
    	bzero(&buffer,sizeof(buffer));
 //读取出来的数据放在缓存区中
        buffer_length = recv(_socketInfo.socketCon,buffer,300,0);
        if(buffer_length == 0)
        {
           printf("%s:%d 客户端关闭\n",_socketInfo.ipaddr,_socketInfo.port);
           printf("errno=%d",errno);
           printf("error:%s\n",strerror(errno));
            conClientCount--;
            break;
          
        }
       else if(buffer_length < 0)
        {
           printf("errno=%d",errno);
            printf("error:%s\n",strerror(errno));
           if(errno==EAGAIN)
{
            printf("接受客户端数据失败\n");
 }           
        }
       else if(buffer_length>0)
       {
        buffer[buffer_length] = '\0';
        printf("%s:%d 说:%s\n",_socketInfo.ipaddr,_socketInfo.port,buffer);
       }
        printf("进入非阻塞测试\n");
        sleep(2);
    }
    
    return NULL;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值