/******************************************************************************************
*
* 程序功能:该程序是进程通信中的服务器端,主要是开启监听,接收客户端传来的
* 数据,产生一个子进程于客户端保持连接,并把接收到的数据压到消息
* 队列中,再有一个子进程从消息队列中读取数据,并写入文件中
*
* 编写时间:2011-7-19
* 版本:1.0
*
*******************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#define SERVPORT 3297 /*服务器的端口号*/
#define BACKLOG 10 /*最大连接数*/
#define MAXSIZE 1024 /*发送和接受的数据的最大字节数*/
#define TRUE 1 /*true的宏定义*/
#define MSG_FILE "server.c" /*一个字符串标识,用来生成消息队列的Key*/
#define PERM S_IRUSR|S_IWUSR /**/
#define FILE "file" /*要存储的文件名,在当前路径下*/
#define FILE_OPEN_MODLE "a+" /*文件打开模式*/
#define QUIT "quit" /*退出标记*/
/**************************************************************************************
*
* 该结构记录了连接到服务器的客户的编号信息,其中client_ip记录
* 客户端的IP地址信息,client_num记录该客户在这个IP地址的编号,
* 编号从1-BACKLOG,编号会从1增长到BACKLOG后,重新从1开始计数,
* 这样通过IP地址和编号就可以较详细且能唯一地表示客户端
*
****************************************************************************************/
struct client_id
{
char *client_ip; /*客户端的IP*/
int client_fd; /*客户端的socket句柄*/
int client_num; /*相应IP的客户端的数量*/
}clients[BACKLOG]; /*直接定义了BACKLOG个客户信息*/
int sockfd; /*socket标识*/
int msgid; /*消息队列的id*/
int client_num = 0; /*客户端的实际连接数量*/
/**************************************************************************************
*
* 该结构记录了消息的类型以及消息的内容
*
****************************************************************************************/
struct msgtype
{
long mtype; /*消息的类型*/
char buffer[MAXSIZE+30];/*消息的内容,传到消息队列中的消息除了客户传来的消息外还有客户的标识,要加30*/
};
/**************************************************************************************
*
* 函数功能:初始化客户端编号的数据
* 输入参数:
* 返回值:返回1表示初始化成功
*
****************************************************************************************/
int clientsInit()
{
int i;
for (i=0; i<BACKLOG; i++)
{
clients[i].client_ip=NULL;
clients[i].client_num=0;
}
return 1;
}
/**************************************************************************************
*
* 函数功能:根据IP地址给该连接一个唯一的客户标识
* 输入参数1:一个IP地址字符串
* 输入参数2:客户的socket句柄
* 返回值:一个clieng_id类型的结构,表示该连接的唯一标识
*
****************************************************************************************/
struct client_id getClient(char *client_ip, int client_fd)
{
int i;
/*判断现在的实际连接数是否达到最大*/
if ((client_num+1) == BACKLOG)
{
client_num = 0;
}
clients[client_num].client_ip = client_ip;/*客户的IP*/
clients[client_num].client_fd = client_fd;/*客户端sicket句柄*/
for (i=0; i<=client_num; i++)
{
if (strcmp(clients[i].client_ip,client_ip) == 0)
{
clients[client_num].client_num++;
}
}
client_num++;
return clients[client_num-1];
}
/**************************************************************************************
*
* 函数功能:获取当前时间,并返回hh:mm:ss格式的时间字符串
* 输入参数:void
* 返回参数:指向时间的字符串指针
* 返回值:一个字符指针,指向时间信息
*
****************************************************************************************/
char* getTime(char time[8])
{
struct timeval tms;
char tstr[8];
timerclear(&tms);
gettimeofday(&tms, NULL);
strftime(time,100,"%X",localtime(&tms.tv_sec));
//strftime(time,100,"%X",localtime(&tms.tv_sec));
return time;
}
/**************************************************************************************
*
* 函数功能:根据客户端的标识信息及穿过来的数据生成详细信息(包含
* 客户标识信息,时间及传输过来的信息
* 输入参数1:一个client_id类型的结构,代表客户的标识
* 输入参数2:msg,客户穿过来的数据
* 返回值:一个字符指针,指向详细信息
*
****************************************************************************************/
char* getmsg(struct client_id client, char *msg)
{
/*先动态分配相应的空间*/
char *mymsg = (char *)malloc(MAXSIZE+30);
//char time[8];
char *time = (char *)malloc(8);
/*将整数转换为字符串*/
char num[30];
memset(num, 0, sizeof(num));
sprintf(num, "%d", client.client_num);
/*获取当前时间的字符串格式*/
getTime(time);
/*进行字符串的拼接,也可以用strcat函数,这边自己写*/
int i,j,k,n;
/*拼接IP地址*/
for (i=0; i<strlen(client.client_ip);i++)
{
mymsg[i] = client.client_ip[i];
}
mymsg[i] = '(';
/*拼接该IP下的编号*/
for (j=0; j<strlen(num); j++)
{
mymsg[i+j+1] = num[j];
}
mymsg[i+j+1] = ')';
j++;
mymsg[i+j+1] = ' ';
j++;
for (n=0; n<strlen(time); n++)
{
mymsg[i+j+n+1] = time[n];
}
mymsg[i+j+n+1] = '\n';
n++;
/*拼接传过来的数据*/
for (k=0; k<strlen(msg); k++)
{
mymsg[i+j+k+n+1] = msg[k];
}
mymsg[i+k+j+n+1] = '\n';
k++;
mymsg[i+k+j+n+1] = '\n';
free(time);
return mymsg;
}
/**************************************************************************************
*
* 函数功能:简单实现字符串的拷贝,且不考虑字符串的溢出情况
* 输入参数1:所拷贝到的字符指针
* 输入参数2:拷贝的字符指针
* 返回值:所拷贝的字符指针
*
****************************************************************************************/
char* mystrcopy(char *to, char *from)
{
int i,j;/*循环变量*/
for (i=0; i<strlen(from); i++)
{
to[i] = from[i];
}
for (j=i; j<strlen(to); j++)
{
to[j] = '\0';
}
return to;
}
/**************************************************************************************
*
* 函数功能:删除消息队列
* 输入参数:消息对列编号
* 返回值:成功返回1
*
****************************************************************************************/
int freemsg(int msgid)
{
if (msgctl(msgid, IPC_RMID, NULL) < 0)
{
exit(1);
}
return 1;
}
/**************************************************************************************
*
* 函数功能:从消息队列中获取消息并写入文件中
* 输入参数:消息对列编号
* 返回值:成功返回1
*
****************************************************************************************/
int getMsgFromMsqToFile(int msgid)
{
int file_fd; /*文件描述符*/
int bytes_read; /*从消息队列中获取的字节数*/
int bytes_write; /*写入文件的字节数*/
char buffer[MAXSIZE]; /*从消息队列中获取的数据所存放的缓冲区*/
char *ptr; /*写入文件的缓冲区*/
struct msgtype msg; /*消息类型及内容*/
/*以只写的方式创建文件*/
if ((file_fd = open(FILE, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) == -1)
{
fprintf(stderr, "Open %s Error:%s\n",FILE,strerror(errno));
exit(1);
}
/*循环从消息队列中读取数据*/
while (T
- 1
- 2
前往页