linux區域網路通訊源碼(伺服器多工和用戶端多進程模式)(socket)伺服器端

來源:互聯網
上載者:User

/* 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);
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.