chat function based on pthread and ipc

//client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#define MAXLEN 1024

/*消息类型*/
struct message
{
  char flag[15];
  char name[10];
  int size;
  char msg[MAXLEN];
};


struct msq
{
  long msg_type;
  char msg_text[5];
};

int qid=-1,fd=-1,sockfd,savefilefd=-1;
char filefromname[10];


void handleQuit(int signal_no)
{
  if(fd>0) close(fd);
  close(sockfd);
  if(qid>0)
    {
      if((msgctl(qid,IPC_RMID,NULL))<0)  //删除消息队列
	{
	  printf("消息队列无法关闭\n");
	  exit(1);
	}
    }
  close(savefilefd);
  printf("程序正常退出\n");
  raise(SIGQUIT);
}

/*******************************************************************
 *功能:切割字符串
 *参数:c为分隔符,left为分割后存放左边字符串,right为分隔后存放右边字符串
 ******************************************************************/
void cutStr(char str[],char left[], int n, char right[],int m, char c)
{
  int i,k,j;
  for(i = 0 ; i < n ;i++)
    {
      if(str[i] == c)
	break;
    }
  if(i == n)
    {
      i = -1;
    }
  else
    {
      memset(left,0,strlen(left));
      for(k = 0 ; k < i ; k++)
	{
	  left[k] = str[k];
	}
    }
  for(j = i+1 ; j < m;j++)
    {
      if(str[j] == '\0')
	break;
      right[j-i-1] = str[j];
    }
  left[i] = '\0';
  if(j < m)
    right[j-i-1] = '\0';
  else
    right[m] = '\0';
}

struct msq msg;
time_t timep;  

void handlerecvmsg(int *sockfd)
{
  int connfd = *sockfd;
  int nread;
  char buf[1024];
  char str[1024];
  struct message recvmsg;
  // time_t timep;
  //struct msq msg;
  if(( fd =open("chatlog.txt",O_RDWR|O_APPEND))< 0)
    {
      perror("打开聊天记录文件失败!");
      exit(1);
    }
  if((qid = msgget(2222,IPC_CREAT|0666)) == -1)
    {
      printf("创建消息队列失败\n");
      exit(1);
    }
  msg.msg_type = getpid();
  strcpy(msg.msg_text,"OK");
  while(1)
    {
      nread = recv(connfd,&recvmsg,sizeof(struct message),0);
      if(nread == 0)
	{
	  printf("与服务器断开了连接\n");
	  close(fd);
	  close(connfd);
	  exit(0);
	}
      else if (strcmp(recvmsg.flag,"all") == 0)     //客户发给所有人
	{
	  time (&timep);
	  sprintf(str,"%s%s发给所有人:%s\n\n",ctime(&timep),recvmsg.name,recvmsg.msg);
	}
      else if (strcmp(recvmsg.flag,"view") == 0)     //查看所有在线用户
	{
	  time (&timep);
	  printf("%s当前在线客户端:\n%s\n\n",ctime(&timep),recvmsg.msg);
	  continue;
	}
      else         //私聊
	{
	  time (&timep);
	  sprintf(str,"%s%s发来的私聊消息:%s\n\n",ctime(&timep),recvmsg.name,recvmsg.msg);
	}
      write(fd,str,strlen(str));    //写文件,保存消息记录
      //printf("%s",msg);
      msgsnd(qid,&msg,sizeof(struct msq),0);
    }
}



int main(int argc,char *argv[])
{
  struct sockaddr_in server_addr;
  int port;
  int do_number;
  struct message a;
  char str[MAXLEN];
  char buf[MAXLEN];
  pthread_t pid;
  if(argc != 3)
    {
      printf("请输入服务器IP和端口\n");
      exit(1);
    }
  port = atoi(argv[2]);
  if((sockfd =
      socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
      printf("创建socket失败\n");
      exit(1);
    }
  signal(SIGINT,handleQuit);
  printf("----------------------------------\n");
  printf("||\n");
  printf("|   input a number to work       |\n");
  printf("|\t1.login\t\t\t |\n");
  printf("|\t2.register\t\t |\n");
  printf("|\t3.exit\t\t\t |\n");
  printf("||\n");
  printf("----------------------------------\n");
  scanf("%d",&do_number);
  gets(str);
  while(do_number != 1 && do_number != 2 && do_number != 3)
    {
      printf("你输入的不是上面的选项,请重新输入:\n");
      scanf("%d",&do_number);
      gets(str);
    }
  if(do_number==3)
    {
      close(sockfd);
      printf("程序已退出!\n");
      exit(0);
    }
  bzero(&server_addr,sizeof(struct sockaddr_in));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(argv[1]);
  server_addr.sin_port = htons(port);
  if(connect(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) == -1)
    {
      printf("与服务器无响应,请隔一段时间再连接\n");
      exit(2);
    }

  if(do_number ==1)          //登陆
    {
      int n = 3;
      while(n)
	{
	  printf("请输入你的用户名:\n");
	  scanf("%s",a.name);
	  printf("请输入密码:\n");
	  scanf("%s",a.msg);
	  strcpy(a.flag,"login");
	  //a.flag[3] = '\0';
	  send(sockfd,&a,sizeof(a),0);
	  printf("正在等待服务器应答...\n");
	  recv(sockfd,buf,MAXLEN,0);
	  printf("接到服务器发来的信息:%s\n",buf);
	  if(strcmp(buf,"登录成功!") == 0)
	    {
	      //int i,j,k;
	      pthread_create(&pid,NULL,(void*)handlerecvmsg,(void *)&sockfd);    //创建线程来处理接收的消息
	      gets(str);
	      strcpy(a.flag,"all");
	      while(1)
		{
		  memset(a.msg,0,strlen(a.msg));
		  memset(str,0,strlen(str));
		  gets(str);
		  strcpy(buf,a.flag);
		  cutStr(str,a.flag,15,a.msg,MAXLEN,'$');
		  printf("标志信息为:%s\n",a.flag);
		  if(strcmp(a.flag,"view") == 0)
		    {
		      send(sockfd,&a,sizeof(a),0);
		      strcpy(a.flag,buf);
		      continue;
		    }
		  else
		    {
		      send(sockfd,&a,sizeof(a),0);
		      time (&timep);
		      sprintf(str,"%s我发给%s的私聊消息:%s\n\n",ctime(&timep),a.flag,a.msg);
		      write(fd,str,strlen(str));
		      msgsnd(qid,&msg,sizeof(struct msq),0);
		      continue;
		    }
		}
	    }
	  else
	    {
	      n--;
	      printf("您还有%d次机会,之后将退出程序!\n",n);
	    }
	}
      close(sockfd);
      exit(3);
    }
 
  else if(do_number ==2)  //注册
    {
      int i =1 ;
      char username[10];
      char password[20];
      char password_t[20];
      char temp[20];
      printf("请输入你的用户名:\n");
      scanf("%s",username);
      while(i)
	{
	  printf("请输入密码:\n");
	  scanf("%s",password);
	  printf("youpass : %s\n",password);
	  printf("请再次输入密码:\n");
	  scanf("%s",password_t);
	  printf("passyou : %s\n",password_t);
	  if(strcmp(password,password_t) != 0)
	    {
	      printf("输入的密码不一样\n");
	      i = 1;
	    }
	  else
	    {
	      i = 0;
	    }
	}
      strcpy(a.name,username);
      strcpy(a.msg,password);
      strcpy(a.flag,"reg");
      //a.flag[3] = '\0';
      send(sockfd,&a,sizeof(a),0);
      printf("正在等待服务器应答...\n");
      recv(sockfd,buf,MAXLEN,0);
      printf("接到服务器发来的信息:%s\n",buf);
    }
  close(sockfd);
  return 0;
}

//display.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
int qid,fd;
struct msq
{
  long msg_type;
  char msg_text[5];
};
void handlequit(int sign_no)
{
  close(fd);
  if((msgctl(qid,IPC_RMID,NULL)) < 0)
    {
      printf("消息队列无法关闭\n");
      exit(1);
    }
  printf("程序正常退出\n");
  raise(SIGQUIT);
}

int main()
{
  char buf[1024];
  int n;
  struct msq msg;
  fd = open("chatlog.txt",O_RDONLY|O_CREAT);
  signal(SIGINT,handlequit);
  if(fd<0)
    {
      printf("打开文件失败\n");
      return -1;
    }
  lseek(fd,0,SEEK_END);
  if((qid = msgget(2222,IPC_CREAT|0666)) == -1)
    {
      printf("创建消息队列失败\n");
      close(fd);
      return -1;
    }
  while(1)
    {
      if(msgrcv(qid,&msg,sizeof(msg),0,0) < 0)
	{
	  printf("读取消息对列失败\n客户端可能已经退出本程序将一起退出\n");
	  close(fd);
	  return -1;
	}
      memset(buf,0,sizeof(buf));
      n = read(fd,buf,1024);
      write(STDOUT_FILENO,buf,n);
    }
  close(fd);
  return 0;
}

//check.c
#include "check.h"

int reg_check(struct message *recievemsg)
{
  int fd;
  int read_size,write_size;
  struct message cmpmsg;
  if(strlen(recievemsg->name)>10 ||
     strlen(recievemsg->msg)>20 )
    {
      return 1;
    }
  if(strcmp(recievemsg->name,"all")==0)
    {
      return -1;
    }
  if(strcmp(recievemsg->name,"reg")==0)
    {
      return -1;
    }
  if(strcmp(recievemsg->name,"login")==0)
    {
      return -1;
    }
  if(strcmp(recievemsg->name,"trans")==0)
    {
      return -1;
    }
  if((fd=open("user.txt",O_RDWR|O_APPEND|0666))<0)
    {
      perror("open");
      printf("open\n");
      return -2;
    }
 do
   {
     if((read_size=read(fd,&cmpmsg,sizeof(cmpmsg)))< 0)
       {
	 perror("read");
	 close(fd);
	 return -2;
       }
     if(read_size != sizeof(struct message) && read_size !=0)
       {
	 close(fd);
	 return -2;
       }
     if(strcmp(recievemsg->name,cmpmsg.name)==0)
       {
	 close(fd);
	 return -1;
       }
   }while(read_size == sizeof(struct message));
 if((write_size=write(fd,recievemsg,sizeof(struct message)))<0)
   {
     perror("write");
     close(fd);
     return -2;
   }
 while(write_size!=sizeof(struct message))
   {
     //write_size = 0-writesize;
     lseek(fd,-write_size,SEEK_CUR);
     write_size=write(fd,recievemsg,sizeof(struct message));
   }
 printf("write file success\n");
 close(fd);
 return 0;
}


int login_check(struct message *recievemsg)
{
  int fd;
  struct message cmpmsg;
  int read_size;
  if((fd=open("user.txt",O_RDONLY))<0)
    {
      perror("open");
      return -2;
    }
 do
   {
     if((read_size=read(fd,&cmpmsg,sizeof(struct message)))<0)
       {
	 perror("read");
	 close(fd);
	 return -2;
       }
     if(read_size != sizeof(struct message) &&
	read_size!=0)
       {
	 close(fd);
	 return -2;
       }
     if((strcmp(recievemsg->name,cmpmsg.name)==0
	 )&&(strcmp(recievemsg->msg,cmpmsg.msg)==0))
       {
	 close(fd);
	 return 0;
       }
   }while(read_size>0);
 close(fd);
 return -1;
}

//check.h
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#define MAXLEN 1024
struct message
{
  char flag[15];
  char name[10];
  int size;
  char msg[MAXLEN];
};
int reg_check(struct message *recievemsg);
int login_check(struct message *recievemsg);

//linklist.c
#include "linklist.h"
LinkList CreateLinkList()
{
  LinkList L = (LinkList)malloc(sizeof(LNode));
  L->next = NULL;
  return L;
}
void deletelist(LinkList L ,datatype e)
{
  int i=0;
  LinkList s,p;
  p = L;
  while ( (strcmp(p->data.name,e.name) != 0) && p->next != NULL)
    {
      s=p;
      p = p->next;
    }
  if (p->next == NULL &&
      (strcmp(p->data.name,e.name) != 0))
    {
      return;
    }
  else
    {
      s->next = p->next;
      free(p);
    }
}
void insertend(LinkList L,datatype e)
{
  int i=0;
  LinkList s,p;
  p = L;
  while(p->next != NULL)
    {
      p = p->next;
      i++;
    }
  s = (LinkList)malloc(sizeof(LNode));
  s->data =e;
  s->next = p->next ;
  p->next =s;
}
void DisplayList(LinkList L)
{
  L=L->next;
  int i = 1;
  while (L != NULL)
    {
      printf("%d. %s   \n",i,L->data.name);
      L = L->next;
      i++;
    }
}

//linklist.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>

/*客户端信息*/
typedef struct _clientinf
{
  char name[10];
  struct sockaddr_in addr_in;
  int decr;
  pthread_t pid;
}clientinf;

typedef clientinf datatype;

/*链表节点*/
typedef struct _LNode
{
  datatype data;
  struct _LNode * next;
}LNode,*LinkList;

extern LinkList CreateLinkList(void);
extern void deletelist(LinkList L ,datatype e);
extern void insertend(LinkList L,datatype e);
extern  void DisplayList(LinkList L);

#server:
server:server.o linklist.o check.o
	gcc server.o linklist.o check.o -lpthread -o server
server.o:server.c check.h linklist.h
	gcc -c server.c
check.o:check.c check.h
	gcc check.c -c
clean:
	rm server.o linklist.o check.o server

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <signal.h>
#include "linklist.h"
#include "check.h"
LinkList clientlink;        //客户端信息链表

/****************************************************
 *功能:处理信息
*****************************************************/
void handlesignal()
{
  int choose;
  char name[10];
  while(1)
    {
      printf("1.T除指定客户端,2.关闭服务器,3.显示在线客户端\n");
      scanf("%d",&choose);
      while(choose < 1 || choose > 3)
	{
	  printf("请输入上面提示的选项:\n");
	  scanf("%d",&choose);
	}
      gets(name);
      if(choose == 1)
	{
	  printf("请输入你踢出去的客户端名字:\n");
	  gets(name);
	  if(strcmp(name,"") == 0) continue;
	  LinkList L,s;
	  L = clientlink;
	  L=L->next;
	  s = L;
	  while((strcmp(L->data.name,name) != 0)
		&& L->next != NULL)
	    {
	      s = L;
	      L = L->next;
	    }
	  //printf("1%s\n",L->data.name);
	  if(L->next == NULL && (strcmp(L->data.name,name) != 0))
	    {
	      printf("该客户端不存在\n");
	    }
	  else
	    {
	      close(L->data.decr);                 //关闭套接字
	      pthread_cancel(L->data.pid);         //关闭对应线程
	      s->next = L->next;
	      free(L);
	    }
	  printf("3\n");
	}
      else if(choose == 2) return;
      else if(choose == 3)
	{
	  DisplayList(clientlink);
	}
    }
}


/***********************************************************
 *函数功能:处理客户请求
 **********************************************************/
void handleclient (clientinf *client)
{
  clientinf clientNode = *client;
  int nread;
  struct message a;
  LinkList transfileNode;
  char buf[MAXLEN],str[MAXLEN];
  while(1)
  {
    nread =recv(clientNode.decr,&a,sizeof(a),0);
    if(nread == 0)
      {
	strcpy(a.flag,"sermsg");
	printf("客户端%s退出\n",clientNode.name);
	deletelist(clientlink ,clientNode);
	LinkList L;
	L = clientlink;
	L=L->next;
	sprintf(buf,"客户端%s退出\n",clientNode.name);
	while(L != NULL)
	{
	  send(L->data.decr,buf,strlen(buf)+1,0);
	  L = L->next;
	}
	return;
      }
    if(strcmp(a.flag,"login") == 0)        //登录
      {
	int i;
	i = login_check(&a);
	if(i == 0)
	  {
	    strcpy(buf,"登录成功!");
	    strcpy(clientNode.name,a.name);
	    insertend(clientlink,clientNode);
	    send(clientNode.decr,buf,strlen(buf)+1,0);
	  }
	else
	  {
	    strcpy(buf,"登录失败!");
	    send(clientNode.decr,buf,strlen(buf)+1,0);
	  }
	continue;
      }
    else if(strcmp(a.flag,"reg") == 0)   //注册
      {
	int i;
	i = reg_check(&a);
	if(i == 0)
	  {
	    strcpy(buf,"注册成功!");
	    strcpy(clientNode.name,a.name);
	    send(clientNode.decr,buf,strlen(buf)+1,0);
	  }
	continue;
      }
    else if (strcmp(a.flag,"all") == 0) //给所有人发消息
      {
	if (strcmp(a.msg,"") != 0)
	  {
	    LinkList L;
	    L = clientlink;
	    L=L->next;
	    strcpy(a.name,clientNode.name);
	    while(L != NULL)
	      {
		send(L->data.decr,&a,sizeof(struct message),0);
		L = L->next;
	      }
	  }
	continue;
      }
    else if(strcmp(a.flag,"view") == 0)  //查看用户列表
    {
      LinkList L;
      int i = 1;
      L = clientlink;
      L=L->next;
      memset(buf,0,strlen(buf));
      while(L != NULL)
	{
	  memset(str,0,strlen(str));
	  sprintf(str,"%d. %s\n",i,L->data.name);
	  strcat(buf,str);   //将消息合成一个消息
	  L = L->next;
	  i++;
	}
      strcpy(a.name,clientNode.name);
      strcpy(a.msg,buf);
      send(clientNode.decr,&a,sizeof(struct message),0);
      continue;
    }
    else              //私聊                                  
      {
	LinkList L;
	L = clientlink;
	L=L->next;
	strcpy(a.name,clientNode.name);
	while(L != NULL)
	  {
	    if (strcmp(L->data.name,a.flag) == 0)
	      {
		send(L->data.decr,&a,sizeof(struct message),0);
		break;
	      }
	    L = L->next;
	  }
	continue;
      }
  }
}


/***********************************************************
 *函数功能:处理接受请求
************************************************************/
void handleaccept(int *serverfd)
{
  socklen_t client_len;
  int sockfd = *serverfd;
  clientinf clientNode;
  struct sockaddr_in client_addr;
  while(1)
    {
      client_len =sizeof(struct sockaddr_in);
      if((clientNode.decr = accept(sockfd,(struct sockaddr *)&client_addr,&client_len)) == -1)
	{
	  printf("接收连接失败\n");
	}
      else
	{
	  printf("与%s:%d连接建立成功\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
	  clientNode.addr_in = client_addr;
	  pthread_create(&clientNode.pid,NULL,(void *)handleclient,(void *)&clientNode);  //只要有连接请求,就创建线程来处理
	}
    }
}



int main(int argc ,char *argv[])
{
  struct sockaddr_in server_addr,client_addr;
  int sockfd,connectfd,port,nread;
  pthread_t pid;
  char buf[MAXLEN];
  char str[MAXLEN];
  if(argc != 2)
    {
      printf("请输入端口\n");
      exit(1);
    }
  if((sockfd =
      socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
      printf("创建socket失败\n");
      exit(1);
    }
  clientlink = CreateLinkList();
  clientlink->data.decr = sockfd;
  port = atoi(argv[1]);
  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(port);
  if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
    {
      printf("绑定端口失败,端口可能被占用\n");
      exit(2);
    }
  if(listen(sockfd,20) == -1)
    {
      printf("监听端口失败\n");
      exit(3);
    }
  printf("正在监听中...\n");
  pthread_create(&pid,NULL,(void*)handleaccept,(void *)&sockfd);
  handlesignal();
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值