server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<signal.h>
#include<time.h>
const int SVKEY=75;
unsigned short port = 8990; // 本地端口
int sockfd;
struct user
{
char id[50];
int connfd;
};
struct user client;
int connfd = 0;
void setserver()
{
//创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket");
exit(-1);
}
//设置本地地址结构体
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr)); // 清空,保证最后8字节为0
my_addr.sin_family = AF_INET; // ipv4
my_addr.sin_port = htons(port); // 端口
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);// ip,INADDR_ANY为通配地址其值为0
//将本地ip、端口与套接字socket相关联起来
int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
if( err_log == -1)
{
perror("binding");
close(sockfd);
exit(-1);
}
//监听,监听套接字改为被动,创建连接队列
err_log = listen(sockfd, 10);
if(err_log == -1)
{
perror("listen");
close(sockfd);
exit(-1);
}
printf("server at port=%d...\n",port);
}
//得到当前系统的时间
void gettime(char *time)
{
struct timeval now;
gettimeofday(&now, NULL);
strcpy(time, ctime(&now.tv_sec));
}
void sendtoall(int connfd,int shmid)
{
char compare[512]="END"; //将END设置为结束通讯的标志
char recv_buf[512] = "";
char send_buf[512]="";
pid_t pid=fork();
if(pid>0)//父进程读发送的消息 同步到共享内存
{
char *buff=(char *)shmat(shmid,NULL,0);
while(recv(connfd, recv_buf, sizeof(recv_buf), 0)>0)
{
if(strcmp(compare,recv_buf)==0) //判断是否断开连接
{
kill(pid,SIGKILL);//杀死子进程
wait(NULL);
printf("client %s closed!\n",client.id);
close(connfd); //关闭已连接套接字
break;
}
bzero(buff,sizeof(buff));
sprintf(buff,"%s:%s",client.id,recv_buf);
bzero(recv_buf,strlen(recv_buf));
}
}
else if(pid==0)//子进程读共享内存的消息
{
char *buff=(char *)shmat(shmid,NULL,0);
while(1)
{
if(strlen(buff)>0)
{
char id[50];
char temp[512];
sprintf(temp,"%s",buff);
/*获取发送信息的id*/
for(int i=0;i<50;i++)
{
if(temp[i]-':'!=0) id[i]=temp[i];///
else break;
}
if(strcmp(id,client.id)!=0)
{
char time[100];
gettime(time);
sprintf(send_buf,"%s\t%s",time,temp);
int s=send(connfd,send_buf,strlen(send_buf),0);
if(s<0) perror("send");
bzero(send_buf,strlen(send_buf));
}
bzero(id,strlen(id));
bzero(buff,strlen(buff));
}
}
}
}
void ctoc(int connfd,int shmchatid)
{
char send_buf[512];
char recv_buf[512];
int fd=open("/home/hujing/hj/idinf",O_RDONLY);
bzero(send_buf,sizeof(send_buf));
read(fd,send_buf,sizeof(send_buf));
close(fd);
int s=send(connfd,send_buf,strlen(send_buf),0);
if(s<0) perror("send");
pid_t pid=fork();
if(pid==0)
{
char *buff=(char *)shmat(shmchatid,NULL,0);
bzero(buff,sizeof(buff));
/*read all friends*/
bzero(send_buf,sizeof(send_buf));
bzero(recv_buf,sizeof(recv_buf));
recv(connfd,recv_buf,sizeof(recv_buf),0);
// 写入共享内存
while(1) if(strlen(buff)==0) break;//当共享内存为空 输入共享内存
sprintf(buff,"%s",recv_buf);
//printf("1.%s %d recv=%s\n",client.id,(int)strlen(recv_buf),recv_buf);
bzero(recv_buf,sizeof(recv_buf));
}
else if(pid>0)
{
char *buff=(char *)shmat(shmchatid,NULL,0);
bzero(buff,sizeof(buff));
while(1)
{
if(strlen(buff)>0)
{ /*获取发送信息的id*/
char temp[512];
sprintf(temp,"%s",buff);
char id[50];
bzero(id,sizeof(id));
for(int i=0;i<50;i++)
{
if(temp[i]-':'!=0) id[i]=temp[i];
else break;
}
//printf("3.%s %s\n",client.id,id);
if(strcmp(id,client.id)!=0)
{
//printf("2.%s recv %s\n",client.id,temp);
int s=send(connfd,temp,strlen(temp),0);
//if(s>0) printf("%d\n",s);
bzero(buff,sizeof(buff));
break;
}
bzero(buff,sizeof(buff));
}
}
wait(NULL);
}
}
void commu(int connfd,int shmid,int shmchatid)
{
char recv_buf[512];
char send_buf[512];
/*read client id*/
recv(connfd, recv_buf, sizeof(recv_buf), 0);
for(int i=0;i<strlen(recv_buf);i++)
client.id[i]=recv_buf[i];
client.connfd=connfd;
int fd=open("/home/hujing/hj/idinf",O_WRONLY|O_APPEND);//将client.id写入文件
sprintf(send_buf,"%s\t",client.id);
write(fd,send_buf,strlen(send_buf));
bzero(send_buf,strlen(send_buf));
bzero(recv_buf,strlen(recv_buf));
close(fd);
/*read client select*/
recv(connfd,recv_buf,sizeof(recv_buf),0);
char select=recv_buf[1];
bzero(recv_buf,strlen(recv_buf));
switch(select)
{
case '1':sendtoall(connfd,shmid);break;//群聊
case '2':ctoc(connfd,shmchatid);break;//私聊
}
}
int main(int argc, char *argv[])
{
setserver();
struct sockaddr_in client_addr;
char cli_ip[INET_ADDRSTRLEN] = ""; //INET...是ipv4的长度
socklen_t cliaddr_len = sizeof(client_addr); //socklen_t 一种数据类型 accept函数中第三个参数的长度必须和int相同 32和64位 下的socklen_t和int长度不同
umask(0000);
int fd=open("/home/hujing/hj/idinf",O_CREAT|O_TRUNC,0777);//存储id
int shmid=shmget(SVKEY,512,IPC_CREAT|0777);//创建共享内存
int shmchatid=shmget(76,512,IPC_CREAT|0777);//创建共享内存
while(1)
{
connfd=0;
//从完成连接队列中提取客户端连接
connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);
if(connfd < 0)
{
perror("accept");
continue;
}
inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
printf("\nclient ip=%s,port=%d,connfd=%d\n", cli_ip,ntohs(client_addr.sin_port),connfd);
pid_t pid=fork();
if(pid==0)
{
close(sockfd);
commu(connfd,shmid,shmchatid);
close(connfd);
exit(0);
}
}
close(sockfd); //关闭监听套接字
return 0;
}
client.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<sys/types.h>
#include<signal.h>
#include<sys/shm.h>
unsigned short port = 8990; // 服务器的端口号
char *server_ip = "127.0.0.1"; // 服务器ip地址
int sockfd;
char send_buf[512] = "";
char recv_buf[512]="";
char compare[512]="END"; //将END设置为结束通讯的标志
char id[50];
void setclient()
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);// 创建套接字
if(sockfd < 0)
{
perror("socket");
exit(-1);
}
// 设置服务器地址结构体
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr)); // 初始化服务器地址
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_port = htons(port); // 端口
inet_pton(AF_INET, server_ip, &server_addr.sin_addr.s_addr); // 转换ip地址格式
// 主动连接服务器
int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(err_log != 0)
{
perror("connect");
close(sockfd);
exit(-1);
}
}
void sendtoall()
{
printf("\tINPUT ANY SENTENCES YOU WANT\n");
pid_t pid=fork();
/*send message*/
if(pid>0)
{
while(1)
{
//printf("%s:",id);
printf(">>>");
scanf("%s",send_buf);
send(sockfd, send_buf, strlen(send_buf), 0); // 向服务器发送信息
if(strcmp(compare,send_buf)==0) //判断是否断开连接
{
kill(pid,SIGKILL);
wait(NULL);
printf("%s close the connection!\n",id);
close(sockfd);
break;
}
bzero(send_buf,strlen(send_buf)); //清空发送缓冲区
}
}
/*receive message*/
else if(pid==0)
{
while(1)
{
int r=recv(sockfd,recv_buf,sizeof(recv_buf),0);
printf("\n\t%s\n",recv_buf);
bzero(recv_buf,strlen(recv_buf));
}
}
}
void sendtoone()
{
/*send chat id*/
bzero(recv_buf,strlen(recv_buf));
recv(sockfd, recv_buf, sizeof(recv_buf), 0);
printf("friends:%s\n",recv_buf);
int fd[2];
int flag=pipe(fd);//创建管道
if(flag==-1) perror("pipe error");
pid_t pid=fork();//创建子进程
if(pid==0)//子进程 接收私聊请求
{
close(fd[0]);
bzero(recv_buf,sizeof(recv_buf));
recv(sockfd, recv_buf, sizeof(recv_buf), 0);
write(fd[1],recv_buf,strlen(recv_buf));
exit(0);
}
else if(pid>0)//父进程 读取后终止
{
close(fd[1]);
printf(">>>chat with and password(number):");
char chatid[50];
char chatkey[20];
scanf("%s %s",chatid,chatkey);
bzero(send_buf,sizeof(send_buf));
sprintf(send_buf,"%s:%s-%s",id,chatid,chatkey);
send(sockfd,send_buf,strlen(send_buf),0);
bzero(send_buf,strlen(send_buf));
read(fd[0],recv_buf,sizeof(recv_buf));
char sendid[50];
char myid[50];
char sendkey[20];
bzero(sendid,sizeof(sendid));
bzero(myid,sizeof(myid));
bzero(sendkey,sizeof(sendkey));
int i=0;
for(;i<(int)strlen(recv_buf);i++)
if(recv_buf[i]-':'!=0) sendid[i]=recv_buf[i];
else break;
i++;
for(int j=0;i<(int)strlen(recv_buf);i++,j++)
if(recv_buf[i]-'-'!=0) myid[j]=recv_buf[i];
else break;
i++;
for(int j=0;i<(int)strlen(recv_buf);i++,j++)
sendkey[j]=recv_buf[i];
//printf("%s %s %s\n",sendid,myid,sendkey);
if(strcmp(sendid,chatid)==0&&strcmp(myid,id)==0&&strcmp(chatkey,sendkey)==0)
{
printf("\tstart communication with %s\n",sendid);
int key=0;
sscanf(sendkey,"%d",&key);
//printf("%d\n",key);
int shmid=shmget(key,512,IPC_CREAT|0777);
pid_t ppid=fork();
if(ppid>0)//子进程 发
{
char *buff=(char *)shmat(shmid,NULL,0);
while(1)
{
printf(">>>");
bzero(send_buf,sizeof(send_buf));
scanf("%s",send_buf);
if(strcmp(compare,send_buf)==0) //判断是否断开连接
{
kill(ppid,SIGKILL);//杀死子进程
wait(NULL);
printf("%s close the connection!\n",id);
close(sockfd); //关闭已连接套接字
break;
}
bzero(buff,sizeof(buff));
sprintf(buff,"%s:%s",id,send_buf);
bzero(send_buf,sizeof(send_buf));
}
}
else if(ppid==0)//父进程 收
{
char *buff=(char *)shmat(shmid,NULL,0);
while(1)
{
if(strlen(buff)>0)
{
char chatid[50];
bzero(chatid,sizeof(chatid));
char temp[512];
bzero(temp,sizeof(temp));
sprintf(temp,"%s",buff);
/*获取发送信息的id*/
for(int i=0;i<50;i++)
{
if(temp[i]-':'!=0) chatid[i]=temp[i];
else break;
}
if(strcmp(chatid,id)!=0)
{
printf("\n\t%s\n",temp);
}
bzero(chatid,sizeof(chatid));
bzero(buff,sizeof(buff));
}
}
}
}
wait(NULL);
}
}
int main(int argc, char *argv[])
{
setclient();
/*send client id*/
printf("your id:");
scanf("%s",id);
send(sockfd,id,strlen(id),0);
/*select communication type*/
printf("\t请选择通讯方式\n");
printf("\t1.client-server-all\n");
printf("\t2.client-client\n");
int select=0;
scanf("%d",&select);
send_buf[0]='*';
switch(select)
{
case 1:send_buf[1]='1';break;
case 2:send_buf[1]='2';break;
}
send_buf[2]='*';
send(sockfd,send_buf,strlen(send_buf),0);
bzero(send_buf,strlen(send_buf));
switch(select)
{
case 1:sendtoall();break;
case 2:sendtoone();break;
}
close(sockfd);
return 0;
}