当前位置: 首页 > news >正文

Linux C 基于tcp多线程在线聊天室

多线程在线聊天室

  • 概述
  • 客户端
  • 服务端

概述

  客户端实现了判单用户登录结果、防止单回车字符发送、保存和显示历史聊天记录(仅自己)、退出聊天室功能。
  服务端实现了验证用户是否已经存在(支持最大64用户连接)支持广播用户进入退出聊天室以及用户聊天内容。

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100
int Socket(int domain,int type,int protocol);
int Connect(int sockfd,struct sockaddr * serv_addr,int addrlen);
void *son_fun(void * arg);
void save(const char * dbuff,const char * nbuff);
void list_history_msg(const char * nbuff);
int main(int argc,char *argv[])
{	char namebuff[512]={0};pthread_t id;//建立监听套接字int socketfd = Socket(AF_INET,SOCK_STREAM,0);//connectSIN   serverinfo;serverinfo.sin_family = AF_INET;serverinfo.sin_port   = htons(atoi(argv[2]));serverinfo.sin_addr.s_addr =  inet_addr(argv[1]);int addrlen = sizeof(SIN);Connect(socketfd,(SA*)&serverinfo,addrlen);//send nameprintf("请输入昵称:\n");gets(namebuff);write(socketfd,namebuff,sizeof(namebuff));char b[20];read(socketfd,b,sizeof(b));if(strstr(b,"已存在")){printf("已存在\n");close(socketfd);return 0;		}//print serve infoprintf("登入成功,服务器:%s 端口:%d\n",inet_ntoa(serverinfo.sin_addr),ntohs(serverinfo.sin_port));//make son threadpthread_create(&id,NULL,son_fun,(void *)&socketfd);//w while(1){//timetime_t t = time(NULL);struct tm *tinfo = localtime(&t);//msgchar readbuff[512] = {0};gets(readbuff);//prevent "\n" send to serve and save to dataif(strlen(readbuff)==0) continue;//determine wheather it is "ls"if(strcmp(readbuff,"ls") == 0) {list_history_msg(namebuff);continue;}//determine wheather it is "quit"if(strcmp(readbuff,"quit") == 0){char sendbuff[618] = {0};sprintf(sendbuff,"%s : %s%s",namebuff,asctime(tinfo),"退出聊天");write(socketfd,sendbuff,sizeof(sendbuff));close(socketfd);exit(0);}//sendchar sendbuff[618] = {0};sprintf(sendbuff,"%s : %s%s",namebuff,asctime(tinfo),readbuff);write(socketfd,sendbuff,sizeof(sendbuff));//save datasave(sendbuff,namebuff);}//关闭close(socketfd);return 0;
}
void list_history_msg(const char * nbuff)
{char path[128];char *line = NULL;size_t len = 0;sprintf(path,"./userdata/%s.txt",nbuff);FILE * fp = fopen(path,"a+");printf("********聊天记录*********\n");while(getline(&line , &len , fp) != -1)printf("%s",line);printf("************************\n");free(line);fclose(fp);
}
void save(const char * dbuff,const char * nbuff)
{char path[128];sprintf(path,"./userdata/%s.txt",nbuff);FILE * fp = fopen(path,"a+");fprintf(fp,"%s\n",dbuff);fclose(fp);
}int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd == -1){perror("socket");exit(1);}return socketFd;
}
int Connect (int sockfd,struct sockaddr * serv_addr,int addrlen)
{int val = connect(sockfd,serv_addr,addrlen);if(val == -1){perror("connect");exit(1);}return 0;
}
void *son_fun(void * arg)
{int readpipefd = *((int *)arg);char readbuff[512]={0};while(1){memset(readbuff,0,sizeof(readbuff));if(read(readpipefd,readbuff,sizeof(readbuff))>0){printf("%s\n\n",readbuff);}else{close(readpipefd);pthread_exit(NULL);}}
}

服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);
void *son_fun(void * arg);
int is_exist(char * username);
void broadcast(char *r,char *n);char Userlist[64][20] = {0};
int Userfdlist[64] = {0};int main(int argc,char *argv[])
{	//建立监听套接字int socketfd = Socket(AF_INET,SOCK_STREAM,0);//需要进行重用地址及其端口号int  opt = 1;setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//绑定信息编写服务器信息SIN   serverinfo;serverinfo.sin_family = AF_INET;		//协议IPV4serverinfo.sin_port   = htons(atoi(argv[2]));	//网络字节序(大端字节序)与主机字节序(小端字节序)  serverinfo.sin_addr.s_addr =  inet_addr(argv[1]);int addrlen = sizeof(SIN);Bind(socketfd,(SA*)&serverinfo,addrlen);//监听Listen(socketfd,MAXBACKLOG);//读写while(1){//等待连接SIN clientinfo;int  clientaddrlen = sizeof(SA);int newfd = Accept(socketfd,(SA*)&clientinfo,&clientaddrlen);printf("客户端地址:%s 端口号:%d\n",inet_ntoa(clientinfo.sin_addr),ntohs(clientinfo.sin_port));//创建子线程pthread_t id;pthread_create(&id,NULL,son_fun,(void *)&newfd);}//关闭close(socketfd);return 0;
}
int is_exist(char * username)
{for(int i = 0 ; i < 10; i++){if(strcmp(username,Userlist[i]) == 0)return 1;}return 0;
}
void *son_fun(void * arg)
{int readfd = *((int *)arg);char readbuff[512] = {0};char namebuff[ 20] = {0};read(readfd,namebuff,sizeof(namebuff));//determine wherther it is existif(is_exist(namebuff)){write(readfd,"已存在",sizeof("已存在"));close(readfd);pthread_exit(NULL);}else{write(readfd,"登录成功",sizeof("登录成功"));char r[50];sprintf(r,"%s %s",namebuff,"进入聊天室");printf("%s\n",r);broadcast(r,namebuff);}//save username and userfdfor(int i=0;i<10;i++){if(strlen(Userlist[i])==0){strcpy(Userlist[i],namebuff);Userfdlist[i] = readfd;break;}}while(1){memset(readbuff,0,sizeof(readbuff));if(read(readfd,readbuff,sizeof(readbuff))>0){if(strlen(readbuff)>0){//printf("%s\n\n",readbuff);//broadcastbroadcast(readbuff,namebuff);if(strstr(readbuff,"退出聊天"))for(int i=0;i<10;i++)if(strcmp(Userlist[i],namebuff)==0){printf("%s\n",readbuff);strcpy(Userlist[i],"\0");close(readfd);pthread_exit(NULL);}}}else{close(readfd);pthread_exit(NULL);}}
}
void broadcast(char *r,char *n)
{for(int i=0 ; i<10 ;i++)//if it is a user and not himselfif(strcmp(Userlist[i],n)!=0 && strlen(Userlist[i])!=0)write(Userfdlist[i],r,strlen(r));
}
int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd ==-1){perror("socket");exit(1);}return socketFd;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{int val = bind(sockfd,my_addr,addrlen);if(val){perror("bind");exit(1);}return 0;
}
int Listen(int s,int backlog)
{int val = listen(s,backlog);if(val == -1){perror("listen");exit(1);}return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{int NEWfd = accept(s,addr,addrlen);if(NEWfd == -1){perror("listen");exit(1);}return NEWfd;
}
http://www.lryc.cn/news/239139.html

相关文章:

  • 代码随想录算法训练营第23期day60|84.柱状图中最大的矩形
  • vue动态获取目录结构进行配置静态路由
  • 产品工程师工作的职责十篇(合集)
  • 图片降噪软件 Topaz DeNoise AI mac中文版功能
  • 【开源】基于Vue.js的车险自助理赔系统的设计和实现
  • 2023年亚太杯数学建模思路 - 案例:粒子群算法
  • Android:Google三方库之Firebase集成详细步骤(一)
  • 企业如何选择一款高效的ETL工具
  • vr编辑器可以解决教育教学中的哪些问题
  • 国外聊天IM — Sendbird
  • Django与Ajax
  • linux日志不循环问题诊断
  • Golang版本处理Skywalking Trace上报数据
  • 【开源】基于Vue和SpringBoot的教学过程管理系统
  • 【python学习】中级篇-图形界面-内置库Tkinter,用于创建图形用户界面(GUI)
  • 【开源】基于JAVA的快递管理系统
  • 伦敦银涨1%内银涨多少才能持平
  • Linux:进度条(小程序)以及git三板斧
  • CSS-表格属性(1)
  • html在线生成二维码(附源码)
  • POS系统完整体系的介绍 Pos终端主密钥MK、DUKPT、PEK、DEK、MEK、TUSN的含义 ---安全行业基础篇7
  • 多普勒流速仪的功能作用是什么?
  • java 数据库 查询 select 2
  • 【前端学java】复习巩固-Java中的对象比较(14)
  • Sentinel 系统规则 (SystemRule)
  • Linux:详解(yum的使用、vim编辑器命令集合以及gcc/g++编译器的使用)
  • 剧情继续:马斯克曝出OpenAI前员工举报信,董事会与奥特曼谈判回归
  • mysql解压版安装步骤linux
  • Program Header Table(转载)
  • 汽车智能座舱/智能驾驶SOC -2