linux局域网通讯源码(服务器多路复用和客户端多进程模式)(socket)服务器端

/* net_select.c */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include<malloc.h>


#define PORT    4321
#define MAX_QUE_CONN_NM   5
#define MAX_SOCK_FD   FD_SETSIZE
#define BUFFER_SIZE   1024

typedef struct user
{
   struct sockaddr_in users_sockaddr;//用户IP
   int user_fd;//用户连接套接字
   char *user_name;//用户别名
   char buf[BUFFER_SIZE];//用户发的信息
   char del[4];//删除下线用户信号标志位
   int rece_id;//目标用户ID
   struct user *Next;
}USER_List,*pUSER_List;


pUSER_List craet_USER_listhead()
{
  pUSER_List pHead=(pUSER_List)malloc(sizeof(USER_List));
  if(pHead==NULL)
  {
   printf("The Dynamic memory allocation is fail\n");
   exit(-1);
  }
   pHead->Next=NULL;
   return pHead; 
}

pUSER_List insert_USERList(pUSER_List p,struct sockaddr_in uaddr,int fd,char *name)
{
 int i=0;
 pUSER_List pNew=(pUSER_List)malloc(sizeof(USER_List));
 if(pNew==NULL)
   {
  printf("The Dynamic memory allocation is fail\n");
  exit(-1);
   }
 
   pNew->users_sockaddr=uaddr;
   pNew->user_fd=fd;

 while(p->Next)
 {
  p=p->Next;
 }
 
 p->Next=pNew;
 pNew->Next=NULL;
 
return;
}
void delet_List(pUSER_List p,int fd)
{
 pUSER_List q;
    do
 {
  q=p;//先保存前一个地址
  p=p->Next;
  if(p->user_fd==fd)
  {
        q->Next=p->Next;
  free(p);
  }
  
 }while(p->Next);
}
void sendlist_usr(pUSER_List p,int sockfd)
{
 USER_List end,buff;
 int sendbytes;
 end.user_fd=6000;
 //送消息给客户端
 while(p->Next)
 {  
  p=p->Next;
  memset(&buff,0,sizeof(USER_List));
  buff.users_sockaddr=p->users_sockaddr;
  buff.user_fd=p->user_fd;
  buff.user_name="w";
  if ((sendbytes = send(sockfd,&buff,sizeof(USER_List), 0)) == -1)
  {
   perror("send");
   exit(1);
  }
 }

 if ((sendbytes = send(sockfd,&end,sizeof(USER_List), 0)) == -1)//发射结束标志
 {
  perror("send");
  exit(1);
 }
 
}

void manypeople_chat_fun(pUSER_List USER,int fd,USER_List buff)
{
 int sendbytes;
 while(USER->Next)
   {
   USER=USER->Next;
   printf("%d\n",USER->user_fd);
   strcpy(USER->buf,buff.buf);
   strcpy(USER->del,buff.del);
   if(USER->user_fd!=fd)
   {
    if ((sendbytes=send(USER->user_fd,USER,sizeof(USER_List), 0)) == -1)
     {
      perror("send");
      exit(1);
     }
   }   
   }
}

void singlepeople_chat_fun(int target,USER_List USER)
{
 int sendbytes;
 if ((sendbytes=send(target,&USER,sizeof(USER_List), 0)) == -1)
 {
     perror("send");
     exit(1);
 }
}
int main()
{
 
 pUSER_List USER,REUSER;
 int sendbytes;
 struct sockaddr_in server_sockaddr, client_sockaddr;
 int sin_size, count;
 fd_set inset, tmp_inset;
 int sockfd, client_fd, fd;
 u_long hbuff;
    char bufsym[5];
 USER=craet_USER_listhead();//创建用户列表文件头
 REUSER=USER;
 USER_List buff;
 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)//创建套接字
 {
  perror("socket");
  exit(1);
 }
 
 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));
 if (bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1)
 {
  perror("bind");
  exit(1);
 }
 
 printf("%s\n",(char *)inet_ntoa(&server_sockaddr.sin_addr));
 if(listen(sockfd, MAX_QUE_CONN_NM) == -1)
 {
  perror("listen");
  exit(1);
 }
 printf("listening....\n");
 
 /*将调用socket函数的描述符作为文件描述符*/
 FD_ZERO(&inset);//初始化套接字集合
 FD_SET(sockfd, &inset);//select()机制中提供一fd_set的数据结构,实际上是一long类型的数组?
 //每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系
 
 while(1)
 {
  tmp_inset = inset;
  sin_size=sizeof(struct sockaddr_in);
  memset(&buff, 0, sizeof(USER_List));
  
  /*调用select函数*/
  printf("select....\n");
  if (!(select(MAX_SOCK_FD, &tmp_inset, NULL, NULL, NULL) > 0))
  {
   perror("select");
   close(sockfd);
   exit(1);
  }
  
  for (fd = 0; fd < MAX_SOCK_FD; fd++)
  {
   if (FD_ISSET(fd, &tmp_inset) > 0)
   {
    if (fd == sockfd)
    { /* 服务端接收客户端的连接请求 */
     if ((client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size))== -1)
     {
      perror("accept");
      exit(1);
     }
     FD_SET(client_fd, &inset);
                    strcpy(buff.del,"inl");//用户上线标志置位
        manypeople_chat_fun(USER,fd,buff);//进入群聊模式把上线信息发给说有在线用户
     strcpy(buff.del,"onl");
        insert_USERList(USER,client_sockaddr,client_fd,"w");//插入登陆用户信息
     printf("%d\n",USER->user_fd);
                    sendlist_usr(USER,client_fd);//把在线的用户发给客户机
    
     //printf(" client IP:%s\n",(char*)inet_ntoa(client_sockaddr.sin_addr));   
    }
    else /* 处理从客户端发来的消息 */
    {
  
     if ((count = recv(fd, &buff,sizeof(USER_List), 0)) > 0)
     {
                        strncpy(bufsym,buff.buf,4);
      if(strcmp(bufsym,"sinp")==0)//如果用户选择私聊
      {
                            singlepeople_chat_fun(buff.rece_id,buff);
      }
      
                        if(strcmp(bufsym,"manp")==0)//如果用户选择公聊
      {
       USER=REUSER;
                      manypeople_chat_fun(USER,fd,buff);
      }
     }
     else  
     {
      close(fd);
      FD_CLR(fd, &inset);
      delet_List(USER,fd);//将下线用户删除在线用户列表
      strcpy(buff.del,"del");
      buff.rece_id=fd;
      manypeople_chat_fun(USER,fd,buff);//给客户端发送由用户离开信号
      strcpy(buff.del,"onl");
      printf("Client %d(socket) has left\n", fd);
     }      
    }  
   } /* end of if FD_ISSET*/
  } /* end of for fd*/
 } /* end if while while*/
 
 close(sockfd);
 exit(0);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值