Linux 下 c 语言 聊天软件
这是我学C语言写的第一个软件,是一个完整的聊天软件,里面包括客户端,和服务器端,可以互现聊天,共享文件,有聊天室等,是一个有TCP和UDP协议的聊天软件,测试过很多次在CENTOS和UBUNTU下都通过,写的简单,但五脏俱全,全部贴出来不保留。运行不了,发信给我,还有个使用指南,我是法语写的,有时间我再写个中文的贴上去。废话不说了,代码来了。
- #ifndef CHATHEAD_H_
- #define CHATHEAD_H_
- #include <arpa/inet.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <time.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <sys/uio.h>
- #include <sys/socket.h>
- #include <sys/shm.h>
- #include <sys/sem.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #define MAXLINE 8000
- #ifndef ASTRING_STRUCT
- struct aString{
- char string[200];
- };
- #endif
- #ifndef HAVE_MESSAGE_STRUCT
- struct chatMessage{
- int statu;
- char type[20],message[1024],contenu[4000];
- };
- #endif
- #ifndef HAVE_bind_STRUCT
- struct chatBind{
- char ip[50],nom[20],salon[20];
- long int port;
- int id_socket;
- };
- #endif
- #ifndef HAVE_bind_STRUCT
- struct chatInfo{
- struct sockaddr_in cliaddr;
- int socket ;
- };
- #endif
- static void
- err_doit(int errnoflag, int error, const char *fmt, va_list ap)
- {
- char buf[MAXLINE];
- vsnprintf(buf, MAXLINE, fmt, ap);
- if (errnoflag)
- snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",
- strerror(error));
- strcat(buf, "/n");
- fflush(stdout); /* in case stdout and stderr are the same */
- fputs(buf, stderr);
- fflush(NULL); /* flushes all stdio output streams */
- }
- void
- err_sys(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- err_doit(1, errno, fmt, ap);
- va_end(ap);
- exit(1);
- }
- void
- err_quit(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- err_doit(0, errno, fmt, ap);
- va_end(ap);
- exit(1);
- }
- #endif /*CHATHEAD_H_*/
上面的是头文件,服务器和客户端都要用的。
- #include "chathead.h"
- char * host_name = "127.0.0.255";
- int port = 6789;
- //struct ip_mreq command;
- struct ip_mreqn command;
- int loop = 1;
- int iter = 0;
- int sin_len;
- char message[256];
- int socket_descriptor;
- struct sockaddr_in sin;
- struct hostent *server_host_name;
- static int sockfd;
- static FILE *fp;
- struct aString as[30];
- int ignoreList(char *string){
- int i;
- for(i=0;i<30;i++){
- //printf("_____/n");
- //printf("string %s list %s resultat %d/n",string,as[i].string,strcmp(string,as[i].string)==0);
- if(strcmp(string,as[i].string)==0){
- return -1;
- break;
- }
- }
- return 0;
- }
- void getMyFichePartage(char *pList){
- DIR *pdir;
- struct dirent *pent;
- strcpy(pList,"");
- if((pdir=opendir("./partage"))==NULL)
- {
- fprintf(stderr,"open dir failed./n");
- }
- while(1){
- pent=readdir(pdir);
- if(pent==NULL)break;
- strcat(pList,"/n");
- strcat(pList,pent->d_name);
- //fprintf(stderr,"%5d %s/n",pent->d_ino,pent->d_name);
- }
- closedir(pdir);
- }
- void delectIgnore(char *p){
- int i;
- for(i=0;i<29;i++){
- if (strcmp(as[i].string,p)==0){
- strcpy(as[i].string,"");
- printf("UN IGNORE OK./n");
- }
- //else{
- // printf("PAS TROUVE./n");
- //}
- }
- }
- void *copyto(void *arg){
- char sendline[MAXLINE];
- struct chatMessage cm;
- int source;
- register int k;
- char buf[4000];
- int i=0;
- while (fgets(sendline,MAXLINE,fp)!=NULL) {
- sscanf(sendline,"%10[^:]:%200[^:]:%200[^/n]",cm.type,cm.message,cm.contenu);
- cm.statu=1;
- if(strcmp(cm.type, "UNIGNORE")==0){
- delectIgnore(cm.message);
- }else if(strcmp(cm.type, "IGNORE")==0){
- printf("IGNORE OK/n");
- memcpy(as[i].string,cm.message,sizeof(struct aString));
- i=i+1;
- }else if(strcmp(cm.type, "FILE")==0){
- if((source=open(cm.contenu,O_RDONLY))<0){
- perror("Problem sur le source");
- }else{
- lseek(source,O_WRONLY,-1);
- write(sockfd,&cm,sizeof(cm));
- while((k=read(source,buf,sizeof(buf)))>0){
- sleep(1);
- strcpy(cm.contenu,buf);
- strcpy(cm.type,"FILELINE");
- printf("type est %s/n",cm.type);
- printf("contenu est %s/n",cm.contenu);
- write(sockfd,&cm,sizeof(cm));
- }
- printf("ENVOYER FICHE EST TERMINE/n");
- close(source);
- }
- }else{
- write(sockfd, &cm, sizeof(cm));
- }
- }
- shutdown(sockfd,SHUT_WR);
- return(NULL);
- }
- void *udpListen(void){
- //------udp-------------------------------
- while(1){
- sin_len = sizeof(sin);
- if(recvfrom(socket_descriptor, message, 256, 0,(struct sockaddr *)&sin, &sin_len) == -1) {
- perror("recvfrom");
- }
- printf("SERVEUR:%s/n", message);
- sleep(1);
- }
- if(setsockopt(socket_descriptor, IPPROTO_IP, IP_DROP_MEMBERSHIP, &command, sizeof(command)) < 0) {
- // perror("setsockopt:IP_DROP_MEMBERSHIP");
- }
- //----------------------------------------
- }
- void str_cli(FILE *fp_arg, int sockfd_arg)
- {
- pthread_t tid;
- pthread_t udp;
- struct chatMessage recvChat,returnMsg;
- int target;
- char nameFile[1024];
- char myListFichier[1024];
- int source;
- char nomDefiche[1024];
- register int k;
- char buf[4000];
- sockfd=sockfd_arg;
- fp=fp_arg;
- returnMsg.statu=1;
- pthread_create(&tid,NULL,copyto,NULL);
- pthread_create(&udp,NULL,udpListen,NULL);
- while (read(sockfd,&recvChat,sizeof(recvChat))==0){
- printf("SERVER SHUTDOWN/n");
- exit (-4);
- }
- while (read(sockfd,&recvChat,sizeof(recvChat))>0){
- if(strcmp(recvChat.type, "TELEFILE")==0){
- printf("Le utilisateur [%s] a telecharge la ficher [%s]./n",recvChat.message,recvChat.contenu);
- strcpy(nomDefiche,"./partage/");
- strcat(nomDefiche,recvChat.contenu);
- if((source=open(nomDefiche,O_RDONLY))<0){
- perror("Problem sur le source");
- }else{
- lseek(source,O_WRONLY,-1);
- strcpy(returnMsg.type,"FILE");
- strcpy(returnMsg.message,recvChat.message);
- strcpy(returnMsg.contenu,recvChat.contenu);
- write(sockfd,&returnMsg,sizeof(returnMsg));
- while((k=read(source,buf,sizeof(buf)))>0){
- sleep(1);
- strcpy(returnMsg.contenu,buf);
- strcpy(returnMsg.type,"FILELINE");
- write(sockfd,&returnMsg,sizeof(returnMsg));
- }
- printf("ENVOYER FICHE EST TERMINE/n");
- close(source);
- }
- }
- if(strcmp(recvChat.type, "GETLIST")==0){
- getMyFichePartage(myListFichier);
- //printf("myListFichier == %s/n",myListFichier);
- printf("Le utilisateur %s a pris votre List fichers partage./n",recvChat.message);
- strcpy(returnMsg.type,"MSG");
- strcpy(returnMsg.message,recvChat.message);
- strcpy(returnMsg.contenu,myListFichier);
- write(sockfd, &returnMsg, sizeof(returnMsg));
- }
- if(strcmp(recvChat.type, "INFO")==0){
- printf("SERVEUR : contenu %s/n",recvChat.contenu);
- }
- else if(strcmp(recvChat.type, "MSG")==0 || strcmp(recvChat.type, "FILE")==0 ||strcmp(recvChat.type, "FILELINE")==0){
- if(ignoreList(recvChat.message)==0){
- if(strcmp(recvChat.type, "FILE")==0){
- strcpy(nameFile,"");
- strcat(nameFile,recvChat.contenu);
- strcat(nameFile,recvChat.message);
- printf("nameFile == %s/n",nameFile);
- if((target=open(nameFile, O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0){
- perror("IMPOSSIBLE DE CREE UNE FICHE!!/n");
- }
- }else if(strcmp(recvChat.type, "FILELINE")==0){
- write(target,recvChat.contenu,strlen(recvChat.contenu));
- }
- printf("CLIENT : message %s,contenu %s/n",recvChat.message,recvChat.contenu);
- }else{
- printf("IL Y A UNE MESSAGE ETE IGNORE/n");
- }
- }
- }
- }
- //--------------------------------------------------------------------------------------
- int main(int argc, char **argv){
- int sockfd;
- struct sockaddr_in servaddr;
- //-----------------------udp----------------------------------
- if((server_host_name = gethostbyname(host_name)) == 0){
- perror("gethostbyname");
- exit(EXIT_FAILURE);
- }
- /*bzero(&sin, sizeof(sin));*/
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
- sin.sin_port = htons(port);
- if((socket_descriptor = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
- /* 调用bind之前,设置套接口选项启用多播IP支持*/
- loop = 1;
- if(setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0){
- perror("setsockopt:SO_REUSEADDR");
- exit(EXIT_FAILURE);
- }
- if(bind(socket_descriptor, (struct sockaddr *)&sin, sizeof(sin)) < 0){
- perror("bind");
- exit(EXIT_FAILURE);
- }
- /* 在同一个主机上进行广播设置套接口,作用是方便单个开发系统上测试多播IP广播 */
- loop = 1;
- if(setsockopt(socket_descriptor, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) {
- perror("setsockopt:IP_MULTICAST_LOOP");
- exit(EXIT_FAILURE);
- }
- /* 加入一个广播组。进一步告诉Linux内核,特定的套接口即将接受广播数据*/
- //command.imr_multiaddr.s_addr = inet_addr("224.1.1.1");
- //command.imr_interface.s_addr = htonl(INADDR_ANY);
- command.imr_multiaddr.s_addr = inet_addr(host_name);
- command.imr_address.s_addr = htonl(INADDR_ANY);
- command.imr_ifindex = 2;
- if(command.imr_multiaddr.s_addr == -1) {
- perror("224.0.0.1 not a legal multicast address");
- exit(EXIT_FAILURE);
- }
- if (setsockopt(socket_descriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0){
- //perror("setsockopt:IP_ADD_MEMBERSHIP");
- }
- //--------------------------------------------------------------
- if (argc != 2){
- printf("problem of argument/n");
- exit(-1);
- }
- if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
- printf("problem of socket/n");
- exit(-1);
- }
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(49156);
- if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
- printf("problem of socket/n");
- exit(-1);
- }
- if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
- err_sys("connect error");
- str_cli(stdin,sockfd);
- exit(0);
- }
- #include "chathead.h"
- time_t ticks;
- char buff[MAXLINE];
- int id_Mp; //id du memore pargage
- struct chatBind* p;
- int id_of_semid;
- int id_of_semget;
- //------udp-------------------------------
- int port = 6789;
- int socket_descriptor;
- struct sockaddr_in address;
- char returnList[1024];
- static FILE *fp2;
- int checkItem(int count,struct chatBind* cb){
- int i;
- for (i=0; i<=count;i++){
- if(strcmp(cb->nom,(p+i)->nom)==0)
- return 0;
- }
- return 1;
- }
- int getList(){
- int ii;
- printf("--------------LIST-------------/n");
- for (ii=0; ii<=9;ii++){
- //if(strcmp((p+ii)->nom,"0")==1){
- printf("NOM [%s], SALON [%s],socket id [%d]/n,",(p+ii)->nom,(p+ii)->salon,(p+ii)->id_socket);
- strcat(returnList,"NOM:");
- strcat(returnList,(p+ii)->nom);
- strcat(returnList,",");
- strcat(returnList,"SALON:");
- strcat(returnList,(p+ii)->salon);
- strcat(returnList," | ");
- //}
- }
- strcat(returnList,"/n");
- printf("--------------LIST-------------/n");
- return 2;
- }
- void bordcast(char *string){
- //-----------------------udp-------------------------------------
- if(sendto(socket_descriptor, string, 1024, 0, (struct sockaddr *)&address, sizeof(address)) < 0) {
- perror("sendto");
- exit(EXIT_FAILURE);
- }
- //---------------------------------------------------------
- }
- //oui 1,non 0
- int bind_nom_and_ip(struct chatMessage* point,int sockfd){
- struct chatBind cb;
- //int ii;
- struct sembuf sb;
- struct semid_ds ds;
- unsigned short array[100];
- int count;
- int returnValeur=0;
- unsigned int len;
- struct sockaddr_in ss;
- getpeername(sockfd,(struct sockaddr*)&ss,&len);
- cb.id_socket=sockfd;
- memcpy(cb.salon,"PUBLIC",sizeof(cb.salon));
- memcpy(cb.nom,point->message,sizeof(cb.nom));
- cb.id_socket=sockfd;
- ds.sem_nsems = 0;
- semctl(id_of_semget, 0, IPC_STAT, &ds);
- semctl(id_of_semget, 0, GETALL,array);
- count=array[0];
- if(checkItem(count,&cb)!=0){
- memcpy(p+count, &cb, sizeof(struct chatBind));
- sb.sem_num = 0;
- sb.sem_op = 1;
- sb.sem_flg = sb.sem_flg & ~IPC_NOWAIT;
- semop(id_of_semget, &sb, 1);
- returnValeur=1;
- }else{
- printf("IP:%s,NOM:%s,SALON:%s,Port:%ld./n",cb.ip,cb.nom,cb.salon,cb.port);
- }
- /*printf("...LIST..../n");
- for (ii=0; ii<=count;ii++){
- printf("NOM [%s], IP [%s], PORT [%d]/n,",(p+ii)->nom,(p+ii)->ip,(p+ii)->port);
- }*/
- return returnValeur;
- }
- int getSockbyNom(char* cp){
- int ii;
- char newOne[1024];
- strcat(cp,"/n");
- sscanf(cp,"%[^/n]",newOne);
- for(ii=0; ii<=9;ii++){
- //printf("/n TEST %s %s %d",(p+ii)->nom,cp,strcmp((p+ii)->nom, cp));
- if(strcmp((p+ii)->nom, newOne)==1){
- //printf("id sockfd ///// %d",(p+ii)->id_socket);
- return (p+ii)->id_socket;
- break;
- }
- }
- return -1;
- }
- void getNometSalonParSocket(char* cp,int socketId){
- int ii;
- for (ii=0; ii<=20;ii++){
- if((p+ii)->id_socket==socketId){
- strcat(cp," NOM:");
- strcat(cp,(p+ii)->nom);
- strcat(cp,",");
- strcat(cp,"DANS SALON:");
- strcat(cp,(p+ii)->salon);
- break;
- }
- }
- }
- void getNomParSocket(char* cp,int socketId){
- int ii;
- for (ii=0; ii<=20;ii++){
- if((p+ii)->id_socket==socketId){
- memcpy(cp,"",sizeof(cp));
- //printf("id de socket de la destination est in a fonction %s /n",cp);
- //printf("id de socket de la destination est in a fonction (p+ii)->nom %s /n",(p+ii)->nom);
- strcat(cp,(p+ii)->nom);
- break;
- }
- }
- }
- int sendMsg(struct chatMessage* cm,int sockfd){
- int returnf=getSockbyNom(cm->message);
- struct chatMessage crm;
- char a[1024];
- printf("cm->message %s",cm->message);
- printf("returnf %d",returnf);
- if(returnf==-1){
- return 4;
- }
- else{
- printf("id de socket de la destination est %d/n",returnf);
- getNomParSocket(a,sockfd);
- memcpy(crm.type,"MSG",sizeof(crm.type));
- memcpy(crm.message,a,sizeof(a));
- memcpy(crm.contenu,cm->contenu,sizeof(crm.contenu));
- memcpy(a,"",sizeof(a));
- write(returnf,&crm,sizeof(crm));
- return 3;
- }
- }
- int getIDofPointbySockId(int sockfd){
- int pointId;
- for (pointId=0; pointId<=20;pointId++){
- if((p+pointId)->id_socket==sockfd){
- return pointId;
- break;
- }
- }
- return -1;
- }
- /* resussi return 5
- * else return 6
- */
- int changeSalon(struct chatMessage* cm,int sockfd){
- if(getIDofPointbySockId(sockfd)==-1){
- return 6;
- }else{
- //change salon
- //printf("get id of table %d/n",getIDofPointbySockId(sockfd));
- memcpy((p+getIDofPointbySockId(sockfd))->salon,cm->message,sizeof((p+getIDofPointbySockId(sockfd))->salon));
- return 5;
- }
- }
- /* resussi return 7
- * else return 8
- */
- int sendMessageSalon(struct chatMessage* cm,int sockfd){
- int t;
- char cp[1024];
- struct chatMessage crm;
- int returnInt=8;
- //cherche nom de salon et envoyer une message à chaque socke
- for (t=0; t<=20;t++){
- if(strcmp((p+t)->salon,cm->message)==0){
- getNomParSocket(cp,sockfd);
- memcpy(crm.type,"MSG",sizeof(crm.type));
- memcpy(crm.message,&cp,sizeof(crm.message));
- memcpy(crm.contenu,cm->contenu,sizeof(crm.contenu));
- printf("________%d/n",(p+t)->id_socket);
- printf("crm.type %s/n",crm.type);
- printf("crm.message %s/n",crm.message);
- printf("crm.contenu %s/n",crm.contenu);
- write((p+t)->id_socket,&crm,sizeof(crm));
- memcpy(cp,"",sizeof(cp));
- returnInt=7;
- }
- }
- return returnInt;
- }
- /* si reussi return 9, sinon return 10 */
- int envoyerFile(struct chatMessage* cm,int sockfd){
- int destinationSocket;
- char sourceName[1024];
- struct chatMessage crm;
- //envoyer file
- printf("Two done %s /n",cm->type);
- destinationSocket=getSockbyNom(cm->message);
- printf("destination Socket est %d/n",destinationSocket);
- if(strcmp(cm->type, "FILE")==0){
- getNomParSocket(sourceName,sockfd);
- strcpy(crm.message,sourceName);
- strcpy(crm.type,"FILE");
- strcpy(crm.contenu,cm->contenu);
- write(destinationSocket,&crm,sizeof(crm));
- return 9;
- }else if(strcmp(cm->type, "FILELINE")==0){
- printf("Three done %s /n",cm->type);
- printf("destinationSocket est dans Fileline %d/n",destinationSocket);
- strcpy(crm.message,sourceName);
- strcpy(crm.type,"FILELINE");
- strcpy(crm.contenu,cm->contenu);
- printf("crm.contenu == %s /n",crm.contenu);
- write(destinationSocket,&crm,sizeof(crm));
- return 10;
- }
- return 11;
- }
- void getMyFichePartage(char *pList){
- DIR *pdir;
- struct dirent *pent;
- strcpy(pList,"");
- if((pdir=opendir("./partage"))==NULL)
- {
- fprintf(stderr,"open dir failed./n");
- }
- while(1){
- pent=readdir(pdir);
- if(pent==NULL)break;
- strcat(pList,"/n");
- strcat(pList,pent->d_name);
- //fprintf(stderr,"%5d %s/n",pent->d_ino,pent->d_name);
- }
- closedir(pdir);
- }
- //12 oui, 13 non
- int getListFiche(struct chatMessage* cm,int sockfd){
- char serveurList[1024];
- struct chatMessage crm;
- int a;
- char nomDuSource[1024];
- if(strcmp(cm->message, "SER")==0){
- getMyFichePartage(serveurList);
- strcpy(crm.message,"");
- strcpy(crm.type,"INFO");
- strcpy(crm.contenu,serveurList);
- printf("Des fichiers partages sous le serveur sont: %s /n",crm.contenu);
- printf("type: %s /n",crm.type);
- printf("sockfd: %d/n",sockfd);
- write(sockfd,&crm,sizeof(crm));
- return 12;
- }
- else{
- a=getSockbyNom(cm->message);
- getNomParSocket(nomDuSource,sockfd);
- if(a!=-1){
- strcpy(crm.message,nomDuSource);
- strcpy(crm.type,"GETLIST");
- strcpy(crm.contenu,"");
- printf("nomDuSource: %s /n",nomDuSource);
- printf("type: %s /n",crm.type);
- printf("sockfd: %d/n",a);
- write(a,&crm,sizeof(crm));
- return 12;
- }
- }
- return 13;
- }
- //14 oui, 15 non
- int telecharger(struct chatMessage* cm,int sockfd){
- struct chatMessage crm;
- int a;
- char nomDuSource[1024];
- char nomDefiche[1024];
- int source;
- register int k;
- char buf[4000];
- if(strcmp(cm->message, "SER")==0){
- strcpy(nomDefiche,"./partage/");
- strcat(nomDefiche,cm->contenu);
- strcpy(crm.type,"FILE");
- strcpy(crm.message,"_SERVEUR");
- strcpy(crm.contenu,cm->contenu);
- printf("nomDefiche %s",nomDefiche);
- printf("sockfd %d",sockfd);
- if((source=open(nomDefiche,O_RDONLY))<0){
- perror("Problem sur le source");
- }else{
- lseek(source,O_WRONLY,-1);
- write(sockfd,&crm,sizeof(crm));
- while((k=read(source,buf,sizeof(buf)))>0){
- sleep(1);
- strcpy(crm.contenu,buf);
- strcpy(crm.type,"FILELINE");
- write(sockfd,&crm,sizeof(crm));
- }
- printf("ENVOYER FICHE EST TERMINE/n");
- close(source);
- }
- return 14;
- }
- else{
- a=getSockbyNom(cm->message);
- getNomParSocket(nomDuSource,sockfd);
- if(a!=-1){
- strcpy(crm.message,nomDuSource);
- strcpy(crm.type,"TELEFILE");
- strcpy(crm.contenu,cm->contenu);
- printf("nomDuSource: %s /n",nomDuSource);
- printf("type: %s /n",crm.type);
- printf("contenu: %s /n",crm.contenu);
- printf("sockfd: %d/n",a);
- write(a,&crm,sizeof(crm));
- return 14;
- }
- }
- return 15;
- }
- int distinger(struct chatMessage* point,int sockfd){
- int returnInt=0;
- if(point->statu==1){
- printf(" general type %s/n",point->type);
- printf(" general message %s/n",point->message);
- printf(" general contenu %s/n",point->contenu);
- if(strcmp(point->type, "NOUVEAU")==0){
- return(bind_nom_and_ip(point,sockfd));
- }else if(strcmp(point->type, "LIST")==0){
- return(getList());
- }else if(strcmp(point->type, "TELE")==0){
- return(telecharger(point,sockfd));
- }else if(strcmp(point->type, "MSG")==0){
- //printf("Type %s Gen %s Contenu %s/n",point->type,point->message,point->contenu);
- return(sendMsg(point,sockfd));
- }else if(strcmp(point->type, "SALON")==0){
- return(changeSalon(point,sockfd));
- }else if(strcmp(point->type, "MSGS")==0){
- return(sendMessageSalon(point,sockfd));
- }else if(strcmp(point->type, "FILE")==0 || strcmp(point->type, "FILELINE")==0){
- printf("First done %s /n",point->type);
- return(envoyerFile(point,sockfd));
- }else if(strcmp(point->type, "LISTF")==0){
- return(getListFiche(point,sockfd));
- }else{
- return 100;
- }
- point->statu=2;
- }
- return returnInt;
- }
- void getNometSalonParIPetPort(char* cp,struct sockaddr_in* s){
- int ii;
- for (ii=0; ii<=20;ii++){
- if(
- strcmp(inet_ntop(AF_INET,&s->sin_addr,buff,sizeof(buff))
- ,
- (p+ii)->ip)==0
- ){
- if(ntohs(s->sin_port)==(p+ii)->port)
- {
- //printf("NOM[%s],SALON[%s]/n",(p+ii)->nom,(p+ii)->salon);
- strcat(cp," NOM:");
- strcat(cp,(p+ii)->nom);
- strcat(cp,",");
- strcat(cp,"DANS SALON:");
- strcat(cp,(p+ii)->salon);
- break;
- }
- }
- }
- }
- void deleteInfo(int socketId){
- int ii;
- for (ii=0; ii<=20;ii++){
- if((p+ii)->id_socket==socketId){
- strcpy((p+ii)->ip,"");
- strcpy((p+ii)->nom,"");
- strcpy((p+ii)->salon,"");
- (p+ii)->id_socket=0;
- (p+ii)->port=0;
- break;
- }
- }
- }
- void str_echo(int sockfd){
- ssize_t n;
- struct chatMessage cm,returnMessage;
- unsigned int len;
- struct sockaddr_in ss;
- int distinge;
- char a[100];
- getpeername(sockfd,(struct sockaddr*)&ss,&len);
- for ( ; ; ) {
- if((n=read(sockfd,&cm,sizeof(cm)))==0) {
- getNomParSocket(a,sockfd);
- strcat(a," EST PARTI ");
- bordcast(a);
- printf("%s",a);
- memcpy(a,"",100);
- deleteInfo(sockfd);
- return;
- }else{
- printf("il y a une nouvelle message/n.");
- distinge=distinger(&cm,sockfd);
- printf("distinge %d/n",distinge);
- if(distinge==0){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"DESOLE,CE NOM EST OCCUPE/n",1024);
- }else if(distinge==1){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"CE NOM EST ACCEPTE./n",1024);
- getNometSalonParSocket(a,sockfd);
- strcat(a," EST ARRIVE ");
- bordcast(a);
- memcpy(a,"",100);
- }else if(distinge==2){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,returnList,1024);
- memcpy(returnList,"",1024);
- }else if(distinge==3){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"MESSAGE EST ENVOYE/n",1024);
- memcpy(returnList,"",1024);
- }else if(distinge==4){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"MESSAGE ENVOYE ECHOC, CAR IL'Y A PAS DE NOM CORRESPONDANT/n",1024);
- }else if(distinge==5){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"VOUS AVEZ CHANGE LE SALON/n",1024);
- }else if(distinge==6){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"CHANGE LE SALON ECHOC/n",1024);
- }else if(distinge==7){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"MESSAGE EST ENVOYE (SALON) /n",1024);
- }else if(distinge==8){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"MESSAGE ENVOYE ECHOC (SALON)/n",1024);
- }else if(distinge==9){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"FILE ENVOYE COMMENCE (SALON)/n",1024);
- }else if(distinge==10){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"FILE ENVOYE TERMINE (SALON)/n",1024);
- }else if(distinge==11){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"FILE ENVOYE ECHOC (SALON)/n",1024);
- }else if(distinge==12){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"PRENDRE LIST REUSSIR./n",1024);
- }else if(distinge==13){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"PRENDRE LIST DE LA FICHIER ECHOC./n",1024);
- }else if(distinge==14){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"TELECHARGER COMMENCER./n",1024);
- }else if(distinge==15){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"TELECHARGER ECHOC./n",1024);
- }else if(distinge==100){
- memcpy(returnMessage.type,"INFO",1024);
- memcpy(returnMessage.contenu,"COMMANDE INCONNU/n",1024);
- }
- /*else{
- memcpy(returnMessage.type,"INFO",1024);
- //memcpy(returnMessage.contenu,"SERVER:CE NOM EST NOT ACCEPTE./n",1024);
- memcpy(returnMessage.contenu,"CE NOM EST NOT ACCEPTE./n",1024);
- }*/
- write(sockfd,&returnMessage,sizeof(returnMessage));
- }
- }
- }
- static void* doit(void *arg){
- int connfd;
- connfd=*((int *)arg);
- pthread_detach(pthread_self());
- str_echo(connfd);
- close(connfd);
- return(NULL);
- }
- void *envoyerMessageParServer(void) {
- char sendline[10];
- struct chatMessage cm;
- //while(fgets(sendline,10,fp2)!=NULL)
- while(scanf("%s",sendline)){
- if(strlen(sendline)>0)
- {
- sscanf(sendline,"%10[^:]:%200[^:]:%200[^/n]",cm.type,cm.message,cm.contenu);
- strcpy(sendline,"");
- if(strcmp(cm.type,"INFO")==0){
- printf("%s/n",cm.message);
- bordcast(cm.message);
- printf("VOUS AVEZ BRODCAST UNE MESSAGE./n");
- }
- }
- }
- }
- int main(int argc, char **argv)
- {
- int listenfd,*iptr;
- struct sockaddr_in servaddr;
- socklen_t clilen;
- pthread_t tid;
- struct sockaddr_in cliaddr;
- pthread_t serveur;
- // udp---------------------------------------------------------------------
- socket_descriptor = socket(AF_INET, SOCK_DGRAM, 0);
- if (socket_descriptor == -1) {
- perror("Opening socket");
- exit(EXIT_FAILURE);
- }
- int opt = 1;
- int len = sizeof(opt);
- setsockopt(socket_descriptor, SOL_SOCKET, SO_BROADCAST, (char *)&opt, len);
- memset(&address, 0, sizeof(address));
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = htonl(INADDR_BROADCAST);
- address.sin_port = htons(port);
- //------------------------------------------------------------------------
- id_Mp = shmget(0x213, sizeof(struct chatBind)*30, 0666|IPC_CREAT|IPC_EXCL);
- p= (struct chatBind* )shmat(id_Mp, 0, 0);
- id_of_semid=2014;
- id_of_semget=semget(id_of_semid, 2, 0666|IPC_CREAT|IPC_EXCL);
- semctl(id_of_semget, 0, SETVAL, 0);// counter pour le memoire partage
- listenfd =socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(49156);
- bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
- listen(listenfd, 1024);
- pthread_create(&serveur,NULL,&envoyerMessageParServer,NULL);
- for ( ; ; ) {
- clilen = sizeof(cliaddr);
- iptr=malloc(sizeof(int));
- *iptr = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
- printf("IL Y A NOUVEAU CLIENT EST ARRIVE IP [ %s], PORT [ %d]./n",
- inet_ntop(AF_INET,&cliaddr.sin_addr,buff,sizeof(buff)),
- ntohs(cliaddr.sin_port)
- );
- printf("son id de socket est %d/n",*iptr);
- pthread_create(&tid,NULL,&doit,iptr);
- }
- exit(EXIT_SUCCESS);
- }
都在这里了,现在贴一个使用说明哦
Rapport du Réseau
Projet Réseau et Communication
Table des matières
Introduction et Remerciements ....................................... page 1
Analyser du cas ................................................................... page 2
Manuel d'utilisation ......................................................... page 2-5
Introduction et Remerciements
Le but de ce projet est pour réaliser un logiciel « chat » sou la systeme de Linux par la langage « c » et « c++ » pour mieux comprendre des protocoles connus de l'internent et vise à mettre en oeuvre des communication entre processus.
Le rôle du serveur qui est s'occupe transmettre des message entre des clients et aussi offre des fonctions pour des clients.
Le
rôle de client peut rejoindre la discussion et parler avec les autre
par le serveur, il peut parler avec un seul client et aussi parler avec
tous dans le salon. Mais d'abord ils faut envoyer leur identifiant par
noter que le serveur, il y a nouveau client est arrivé. Le serveur va
vérifier si ce nom est unique ou pas. Une fois que le client est
correctement identifié, il peut alors commencer à envoyer des messages
et recevoir des message par « Chat ».
Par ce projet, on a mieux compris les différence entre des protocoles, et compris comment travaille avec « processus » sous linux.
C'est vraiment de la chance pour nous faire la pratique. Et nous remercions sincèrement de notre professeurs pour votre aider.
Analyser du cas
1,Udp ,Tcp ou avec deux?
D'aborde, le plus importants est choir un protocole pour réaliser le « chat ».
TCP ou UDP, on considère le priorité de TCP est un protocole de
transport fiable et on peut le utilise pour envoyer des messages et
recevoir des message entre le serveur et des clients,car Le côté client de la connexion effectue une ouvertureactive en 3 temps (poignée de mains en trois temps).
Mais,
les broadcast ont lieu au niveau des adresses destination : mac et IP
pas au niveau des protocoles . l'adressage dans ces protocoles se fait
par les ports, il n'y a pas de port broadcast comme il y a une adresse
broadcast . par contre, UDP peut être transporté dans des paquets
broadcast car il fonctionne en mode non connecté tandis que TCP ne peut
pas être transporté dans des paquets broadcast car il fonctionne en mode
connecté .
On utilise le protocole UDP pour réaliser la fonction de « broadcast »,
par exemple le serveur peut envoyer des message à tout les clients
comme des fonctions PARTANTS et utilise le protocole TCP pour prendre
les commandes comme LIST, NOUVEAU, MESSAGE etc.
2,Structure de Message
Le but de ce outil est envoyer des messages et recevoir des messages entre des client, on définit la structure de message ci-dessous:
-
struct chatMessage {
int statu; //définit le statue de message, lire pas encore lire etc.
char type[20]; //définit le type de message,
char message[1024]; //définit des information de ce message
char contenu[1024]; //contenu de ce message,
};
Tableau 1 chathead.h
Grâce à ce structure, on peut très facile de distinguer et traiter des différents messages.
3,Threads et Verrous
A côte de serveur, on utiles « thread » pour connecter avec chaque client, lorsqu'il y a un client arrive, le serveur traite le connections avec crée un nouveau « thread »,
et chaque processus offrent un mécanisme permettant à un processus de
réaliser plusieurs unités d'exécution de façon asynchrone.
Et
on utiles la fonction « verrous et variables conditionnelles car les
verrous permettent de partager facilement des données communes
accessibles en lecture et écriture. Par exemple le serveur qui stocke
les base de donnée pour permet des clients communiquer avec serveur par
différence ID de«socket »,beaucoup de tâche travaillent sur un même serveur.
4,La tableau de stockage
on utilise une structure pour attacher un « Id de socket »à un vrai nom de utilisateur,lorsqu'un client arrive, le serveur enregistre ce nom avec son « socket »,
et puis lorsqu'il part, on le supprime avec une fonction qui peut
tester la statue de ce utilisateur, et tous les information sont stocké
par une mémoire partagé. La structure de message ci-dessous:
-
struct chatBind
{
char ip[50]; // définit IP de chaque clientchar nom[20]; // définit nom de ce client correspondant
char salon[20]; // définit ce client dans lequel salon
long int port; // définit le port de ce utilisateur
int id_socket; // définit le ID de socket de ce connections
};Tableau 2 chathead.h
Manuel d'utilisation
D'abord,
on démarre le serveur,qui attende des clients arrivent, l'address de
serveur est local,c'est-à-dire il est « 127.0.0.1 »:
-
wei@wei-laptop:~/workspace/chat$ ./serveur
Et puis on démarre deux clients,et l'argument de client est l'address de serveur:
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
En
même temps on peut vois à côte de serveur qui déserte qu'il a deux
clients arrivent, et imprimer deux phases sur l'écran,comme au ci-dessous:
-
wei@wei-laptop:~/workspace/chat$ ./serveur
IL Y A NOUVEAU CLIENT EST ARRIVE IP [ 127.0.0.1], PORT [ 45122].
son id de socket est 5
IL Y A NOUVEAU CLIENT EST ARRIVE IP [ 127.0.0.1], PORT [ 45123].
son id de socket est 6
En
suite on enregistre le nom de client par le fonction « NOUVEAU » à côte
de client, ici on enregistre deux client, il s'appelle AAA, et l'autre
s'appelle BBB.
Si
ce nom est unique, il peut recevoir une message par serveur « SERVEUR :
type INFO ,contenu CE NOM EST ACCEPTE. »,si non, il peut recevoir une
message comme « SERVEUR : CE NOM EST OCCUPE ».
Lorsque
le nom est accepté, le serveur utiliser la communication de type
BROADCAST à tout le monde. « SERVEUR: NOM:AAA ,DANS SALON:public EST
ARRIVE » .Au début tout les clients sont dans le salon « public ».
-
wei@wei-laptop:~/workspace/chat$ ./ client 127.0.0.1
NOUVEAU:AAA
SERVEUR : type INFO ,contenu CE NOM EST ACCEPTE.
SERVEUR: NOM:AAA ,DANS SALON:public EST ARRIVE .
SERVEUR: NOM:BBB ,DANS SALON:public EST ARRIVE .
LIST ,liste les noms de tous les participants à la discussion:
-
wei@wei-laptop:~/workspace/chat$ ./ client 127.0.0.1
LIST:
SERVEUR :
NOM:AAA ,SALON:public |
NOM:BBB ,SALON:public |
MESSAGE(MSG) permet d'envoyer des messages par un client pour d'autre client, ici client AAA envoie une message au client BBB;
-
wei@wei-laptop:~/workspace/chat$ ./ client 127.0.0.1
MSG:BBB:Bonjour
Et client BBB qui reçoit une message au ci-dessous:
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
Tu a reçu une message de AAA, contenu est: Bonjour
« IGNORE »
fonction permet de client ne recevoir pas des message de quelqu'un,par
exemple, AAA veut ignorer des message de BBB,il est possible de faire
comme au ci-dessous:
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
IGNORE:BBB
IGNORE OK
Lorsque BBB envoie une message à AAA,AAA peut revoie une message comme au ci-dessous:
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
IGNORE:BBB
IGNORE OK
IL Y A UNE MESSAGE ETE IGNORE
La commande « UNIGNORE » peut enlever le fonction « IGNORE »
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
UNIGNORE:BBB
UNIGNORE OK
Pour
changer un salon, il est possible de utiliser le commande « SALON: nom
de salon », s'il a réussi, le serveur réponde une message «TU A CHANGE LE SALON. » :
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
SALON:MUSIC:
TU A CHANGE LE SALON.
Et
c'est aussi possible de envoyer à tous dans le même salon par un client,
il faut utiliser le commande, « MSGS:nom de salon:votre parole », et
tous dans ce salon peut le recevoir.
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
MSGS:MUSIC: tu aime la music ou pas...
Pour envoyer une fiche,c'est possible de faire avec le commande « FILE: nom : répertoire de fiche », comme au ci-dessous:
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
FILE:AAA:./test.c
Si
quelque client part, tout le monde peut recevoir une message « Le
utilisater AAA est parti », si le serveur part, tout les utilisateur
peut prendre une message aussi, comme « SERVEUR SHUTOWN ».
Et en plus, le serveur peut utiliser une commande pour envoyer une message à tous, au ci-dessous:
-
wei@wei-laptop:~/workspace/chat$ ./serveur
INFO: Le serveur va démarrer dans 30 min.
Pour
lister des fichier des fichiers présents sur le serveur, il permet de
utiliser la commande « LISTF:SER: », et « TELE:SER:nom de fichier »pour
la récupérer.
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
LISTF:SER:
contenu présent sur le serveur
hello.txt
for.in
god.c
TELE:SER:hello.txt
envoyer terminer.
Pour
lister des fichier des fichiers présents sur un autre client, il permet
de utiliser la commande « LISTF:nom de client: », et « TELE:nom de
client :nom de fichier »pour la récupérer.
-
wei@wei-laptop:~/workspace/chat$ ./client 127.0.0.1
LISTF:BBB:
contenu présent sur le BBB
a.txt
b.txt
c.txt
TELE:BBB:a.txt
envoyer terminer.
Linux 下 c 语言 聊天软件的更多相关文章
- linux 下C语言学习路线
UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...
- LINUX下C语言编程基础
实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用 ...
- Unix和Linux下C语言学习指南
转自:http://www.linuxdiyf.com/viewarticle.php?id=174074 Unix和Linux下C语言学习指南 引言 尽管 C 语言问世已近 30 年,但它的魅力仍未 ...
- linux下常用语言的语法检查插件整理
linux下常用语言的语法检查插件 可以结合vim语法检查插件syntastic使用,具体请参考syntastic使用说明 如php,sql,json,css,js,html,shell,c等语法插件 ...
- Windows10下配置Linux下C语言开发环境
今天为大家介绍如在Windows10下配置Linux下C语言开发环境,首先安装linux子系统:启用开发者模式 1.打开设置 2.点击更新和安全3.点击开发者选项 4.启用开发人员模式 5.更改系统功 ...
- Linux下C语言编程实现spwd函数
Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...
- Linux基础与Linux下C语言编程基础
Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...
- Linux下p2p的聊天功能实现
Linux下p2p的聊天功能实现细节 Do one thing at a time, and do well. 今天闲着没事,写一个P2P的点对点的聊天功能的小程序,我觉得对网络编程初学者的学习很有用 ...
- LINUX下中文语言包的安装(转)
在安装盘上已经有各种语言包了,我们只需要找到他们,并安装就可以了.中文的是fonts-chinese-3.02-9.6.el5.noarch.rpmfonts-ISO8859-2-75dpi-1.0- ...
随机推荐
- USB2.0学习笔记连载(五):EZ-USB重要寄存器的配置
本篇博客主要讲解EZ-USB一些重要寄存器的配置,首先对于本篇博客所讲的内容,读者应该到官网上去下载相关的手册,其中包括<EZ-USB Technical Reference Manual> ...
- Linux之查看切换Shell
1.查看存在的shell cat /etc/shells 2.查看使用的shell echo $SHELL 3.切换shell 切换bash chsh -s /bin/bash 切换zsh chsh ...
- ABAP--如何创建自定义打印条码
ABAP--如何创建自定义打印条码 BARCODE in Smartforms: How to create customize BARCODE for Smartforms. 1 Introduct ...
- python 读写配置文件
使用python读写配置文件,写个demo测试一下. #!/usr/bin/env python import os import ConfigParser # 如果文件不存在,就穿件文件. if o ...
- 转:关于VS2012连接MySql数据库时无法选择数据源
原文来自 http://www.cnblogs.com/sanduo8899/p/3698617.html 您的C#开发工具是用VS2012吗? No! return; 您的数据库用的 ...
- [mysql-Ver5.6.23] windows版my.ini配置
基于utf8mb4比utf8多了种编码,能更好的支持emoji表情(http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.htm ...
- chrome浏览器表单自动填充默认样式(背景变黄)-autofill
之所以出现这样的样式, 是因为Chrome会自动为input增加如下样式. 这个样式的优先级也比较高. 无法通过important覆盖(这就比较恶心了). 解决方案(3种): 1. 关闭自动保存账号密 ...
- [Learn AF3]第二章 App Framework 3.0的组件View——AF3的驱动引擎
View:af3中的驱动引擎 组件名称:View 使用说明:按照官方的说法,view组件是af3的“驱动引擎(driving force)”,view是af3应用的基础,一个app中可以包 ...
- font-awesome 使用方法
需要引入文件 font-awesome.css <link rel="stylesheet" href="{$yf_theme_path}public/font-a ...
- Mongodb数据结构及与MySql对比
MySql一直是性价比最高的关系型数据库典范 MongoDB带来了关系数据库以外的NoSql体验. 让我们看一个简单的例子,我们将如何为MySQL(或任何关系数据库)和MongoDB中创建一个数据结构 ...