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.