linux下用C语言写的聊天程序
要求:两个客户端可以进行聊天,服务器用来中转信息。我的主要思路是:对于每个客户端连接,服务器端建立子进程对其进行处理,注册消息格式:register aa bb(aa是用户名,bb是密码),服务器根据第一个字符串对其进行处理;登陆:login aa bb,登陆成功后可以进行chat、logout等后续操作,当收到chat dd hello时,便找到dd的socket地址和文件描述符,将消息转发给他。
可这时我发现消息根本无法转发,每个客户端连接时的new_fd都相同,消息只能回发给aa,这里我应该怎么实现呢,我看了好多程序,都是用线程,我想用子进程实现,希望大家提供点思路。。下面是我服务器端的代码
程序代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <error.h> #include <unistd.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/stat.h> #include <fcntl.h> #define MAXDATASIZE 256 #define PORT 3000 #define BACKLOG 5 #define TM_L 14 struct users { char name[50]; char password[50]; char state[5]; char IP[20]; long port; int fd; }; typedef struct users user; //定义查询函数 int selectdb(user **cl,int f) { int i = sizeof(user); long length = lseek(f,0,SEEK_END); if (length < i) { *cl == malloc(20); puts("empty"); return -1; } if (*cl != NULL) { free(*cl); } *cl = malloc(length); lseek(f,0,SEEK_SET); if (read(f, *cl, length) != length) { perror("error"); return -2; } return 0; } //打印文件内容 void printdb(user * cl,int f) { int i = sizeof(user); long length = lseek(f,0,SEEK_END); int j; char btime[TM_L + 1] = {0}; char name[10] = {0}; for (j = 0; j<length/i; j++) { memcpy(name,(cl+j) -> name, 10); //memcpy(btime, (cl+j) -> btime,TM_L); printf ("%s,%s,%s,%s,%ld,%d\n", name, (cl+j) ->password, (cl+j) ->state,(cl+j)->IP,(cl+j)->port,(cl+j)->fd ); } } //检测登陆是否成功 int check(user * cl,int f,char * name,char * password) { int i = sizeof(user); long length = lseek(f,0,SEEK_END); int j; for (j=0; j<length/i; j++) { if (strcmp((cl+j)->name,name) == 0 && strcmp((cl+j)->password,password) == 0) return j; } return -1; } //插入 int insertdb(user * cr,int f,user *cl) { int i; i = sizeof(user); int length = lseek(f,0,SEEK_END); //cr->id = (cl + (length/i) - 1)->id + 1; lseek(f,0,SEEK_END); if (write(f,cr,i) != i) { perror("error"); return -1; } return 0; } //修改文件 int changedb(user * cc, int f, user *cl) { int i = sizeof(user); long length = lseek(f,0,SEEK_END); long j; for (j=0; j<= length/i; j++) { if (strcmp((cl+j) -> name, cc -> name) == 0) break; } printf ("nihao"); memcpy(cl+j,cc,i); lseek(f,0,SEEK_SET); printf ("%s\n",cl->name); if (write(f,cl,length) != length) { perror("error"); return -1; } return 0; } //根据人名找到他的socket地址 struct sockaddr_in addr(char * name, int f, user *cl) { struct sockaddr_in toaddr; bzero(&toaddr,sizeof(toaddr)); toaddr.sin_family = AF_INET; int i = sizeof(user); long length = lseek(f,0,SEEK_END); long j; for (j=0; j<= length/i; j++) { if (strcmp((cl+j) -> name, name) == 0) break; } toaddr.sin_port = (cl+j) -> port; printf ("%ld\n",(cl+j) -> port); if (inet_aton("127.0.0.1",&toaddr.sin_addr) == 0) { printf ("addr convert error\n"); exit(1); } return toaddr; } //根据人名找到他的文件描述符 int fd(char * name, int f, user *cl) { int fd; int i = sizeof(user); long length = lseek(f,0,SEEK_END); long j; for (j=0; j<= length/i; j++) { if (strcmp((cl+j) -> name, name) == 0) break; } printf ("(cl+j)->fd: %d\n",(cl+j)->fd); fd = (cl+j)->fd; return fd; } //根据socket找人名 char * name(struct sockaddr_in fromaddr, int f, user *cl) { char * name = (char *)calloc(10,sizeof(char)); int i = sizeof(user); long length = lseek(f,0,SEEK_END); long j; for (j=0; j<= length/i; j++) { if ((cl+j) -> port == fromaddr.sin_port) break; } printf ("%s\n",(cl+j)->name); strcpy(name, (cl+j) -> name); return name; } int main() { user cr[10]; user *cl; user cc; cl = NULL; int sockfd, sin_size, new_fd,nbytes; int i=0,loca[10],j=0,k,flag=0; char buf[MAXDATASIZE]; struct sockaddr_in srvaddr,clientaddr; char * p,*p1,*p2,*p3,*p4; char command[10],cmd[10]; int client[10]; user user[100]; char bufp[200]; int len; int f; int res; FILE * fp1,*fp2; char file[50]; //创建套接字 sockfd = socket(AF_INET,SOCK_STREAM,0); if (sockfd == -1) { printf ("create sockfd error!\n"); exit(1); } //为套接字分配地址 bzero(&srvaddr,sizeof(srvaddr)); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons(PORT); if (inet_aton("127.0.0.1",&srvaddr.sin_addr) == 0) { printf ("IP address transfer error!\n"); close(sockfd); exit(1); } //绑定服务器 if (bind(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr)) == -1) { printf ("bind error!\n"); close(sockfd); exit(1); } //监听端口 if (listen(sockfd,BACKLOG) == -1) { printf ("listen error\n"); close(sockfd); exit(1); } f = open("qq.txt",O_RDWR | O_CREAT,0664); if (f == -1) { perror("error"); return 1; } for(;;) { //接收客户端连接 sin_size = sizeof(struct sockaddr_in); new_fd = accept(sockfd,(struct sockaddr *)&clientaddr,&sin_size); printf ("new_fd:%d\n",new_fd); if (new_fd == -1) { printf ("accept error!\n"); continue; } printf ("new_fd:%d\n",new_fd); if (!fork()) { close(sockfd); //接收客户端消息 nbytes = read(new_fd,buf,sizeof(buf)); buf[nbytes] = '\0'; printf ("receive message from client: %s\n",buf); strcpy(bufp,buf); p = strtok(buf," "); strcpy(cmd,p); printf ("%s\n",cmd); printf ("%d\n",strcmp(cmd,"login")); /*提取命令字——用户注册*/ if (strcmp(cmd,"register") == 0) { p1 = strtok(NULL," "); strcpy(cr[i].name,p1); p2 = strtok(NULL," "); strcpy(cr[i].password,p2); strcpy(cr[i].state,"out"); insertdb(&cr[i], f, cl); res = selectdb(&cl,f); if (res == -2) { return 1; } else if(res == 0) { printdb(cl,f); } bzero(buf,sizeof(buf)); strcpy(buf,"you have register successfully!"); write(new_fd,buf,sizeof(buf)); printf ("send messge to qqclient:%s\n",buf); } /*提取命令字——登陆及后续操作*/ if (strcmp(cmd,"login") == 0) { p1 = strtok(NULL," "); p2 = strtok(NULL," "); int m=0; res = selectdb(&cl,f); m = check(cl,f,p1,p2); if (m >= 0) { strcpy(cc.name,p1); strcpy(cc.password,p2); strcpy(cc.state,"on"); strcpy(cc.IP,inet_ntoa(clientaddr.sin_addr)); cc.port = clientaddr.sin_port; cc.fd = new_fd; selectdb(&cl,f); changedb(&cc,f,cl); strcpy(buf,"you have login successfully!"); write(new_fd,buf,sizeof(buf)); printf ("send messge to qqclient:%s\n",buf); bzero(buf,sizeof(buf)); res = selectdb(&cl,f); if (res == -2) { return 1; } else if(res == 0) { printdb(cl,f); } } while(1) { //接收客户端消息 nbytes = read(new_fd,buf,sizeof(buf)); buf[nbytes] = '\0'; printf ("receive message from client: %s\n",buf); p = strtok(buf," "); strcpy(cmd,p); if (strcmp(cmd, "chat") == 0) { struct sockaddr_in toaddr; char fromname[10]; char ss[10]; printf ("%s\n",buf); p1 = strtok(NULL," "); p2 = strtok(NULL," "); strcpy(ss,p1); res = selectdb(&cl,f); printf ("%d\n",clientaddr.sin_port); printf ("%s\n",name(clientaddr, f, cl)); strcpy(fromname,name(clientaddr, f, cl)); printf ("%s %s\n",p1,p2); toaddr = addr(p1,f,cl); int fdd; printf("p1:%s\n",p1); fdd = fd(p1, f, cl); printf ("to port:%d\n",toaddr.sin_port); sprintf(buf,"%s%s%s%s%s",cmd," ",fromname," ",p2); printf ("%s\n",buf); //write(new_fd,buf,sizeof(buf)); printf("p1:%s\n",p1); printf ("judge:%d\n",fdd); printf ("to port:%d %d\n",toaddr.sin_port,clientaddr.sin_port); sendto(fdd,buf,strlen(buf),0,(struct sockaddr *)(&toaddr),sizeof(clientaddr)); printf ("send message:%s\n",buf); } } } close(new_fd); exit(0); } close(new_fd); n--; } close(sockfd); return 0; }