jchat:linuxチャット3:サーバ
43619 ワード
makefile:
main.c:主関数
process.c:サブプロセスは、クライアントから送信されたすべてのリクエストを処理するために使用されます.
process.h:
sql.c:mysqlの新しい接続
sql.h:
jchat_server: main.o process.o sql.o
gcc -o jchat_server main.o process.o sql.o -L/usr/lib/mysql -lmysqlclient
rm -f *.o *.gch *~
main.o: main.c process.h sql.h
gcc -c main.c process.h sql.h -I/usr/include/mysql
process.o: process.h process.h
gcc -c process.c process.h -I/usr/include/mysql
sql.o: sql.c sql.h
gcc -c sql.c sql.h -I/usr/include/mysql
clean:
rm -f *.o *.gch *~ jchat_server
main.c:主関数
/*server/main.c*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include "process.h"
#include "sql.h"
#define MAXLINE 4096
#define LISTENQ 1024
#define PORT 12345
int listenfd;
pid_t pid_online_time, pid_conn;
/*
* init server create socket
*/
void server_init()
{
listenfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
}
int main(int argc, char *argv[])
{
server_init();
pid_online_time = fork();
if (pid_online_time == 0) {
refresh_online_time();
}
while (1) {
struct sockaddr_in cliaddr;
int clilen = sizeof(cliaddr);
int connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
if ((pid_conn = fork()) == 0) {
close(listenfd);
process(connfd);
}
else {
pid_t pid = getpid();
//printf("fork process pid = %d
", pid);
}
close(connfd);
}
exit(0);
}
process.c:サブプロセスは、クライアントから送信されたすべてのリクエストを処理するために使用されます.
/*server/process.c*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include "process.h"
#include "sql.h"
#define MAXLINE 4096
char sendbuff[MAXLINE], recvbuff[MAXLINE];
int recv_len;
/*
* all users' online time - 1 every second
*/
void refresh_online_time()
{
MYSQL *conn = sql_init();
while (1) {
mysql_query(conn, "update jchat.user set online_time=online_time-1 \
where online_time>0;");
//printf("refresh online time -1
");
sleep(1);
}
}
/*
* regist new user
* fail when user exists already
*/
void regist(int sockfd)
{
MYSQL *conn = sql_init();
int i, j, k, l;
i = 2;j = 3;
while (recvbuff[j] != ':') ++j;
k = j + 1;
char user[30], passwd[30];
for (l=i; l<j; ++l) {
user[l-i] = recvbuff[l];
}
user[j-i] = '\0';
for (l=k; l<recv_len; ++l) {
passwd[l-k] = recvbuff[l];
}
user[recv_len-k] = '\0';
char query[107];
sprintf(query, \
"select * from jchat.user where user='%s';", \
user);
mysql_query(conn, query);
MYSQL_RES *res = mysql_use_result(conn);
MYSQL_ROW row = mysql_fetch_row(res);
if (row != NULL) { // exist user
sendbuff[0] = 'n';sendbuff[1] = '\0';
}
else {
sendbuff[0] = 'y';sendbuff[1] = '\0';
sprintf(query, \
"insert into jchat.user values('%s','%s',0);", \
user, passwd);
mysql_query(conn, query);
}
mysql_free_result(res);
write(sockfd, sendbuff, strlen(sendbuff));
//printf("sendbuff> '%s'
", sendbuff);
sql_exit(conn);
printf("regist user=%s passwd=%s
", user, passwd);
}
/*
* login a user
* fail if user and password not match
*/
void login(int sockfd)
{
MYSQL *conn = sql_init();
int i, j, k, l;
i = 2;j = 3;
while (recvbuff[j] != ':') ++j;
k = j + 1;
char user[30], passwd[30];
for (l=i; l<j; ++l) {
user[l-i] = recvbuff[l];
}
user[j-i] = '\0';
for (l=k; l<recv_len; ++l) {
passwd[l-k] = recvbuff[l];
}
user[recv_len-k] = '\0';
char query[107];
sprintf(query, \
"select * from jchat.user where user='%s' and passwd='%s';", \
user, passwd);
mysql_query(conn, query);
MYSQL_RES *res = mysql_use_result(conn);
MYSQL_ROW row = mysql_fetch_row(res);
if (row != NULL) { // user and passwd correct
sendbuff[0] = 'y';sendbuff[1] = '\0';
sprintf(query, \
"update jchat.user set online_time=7 \
where user='%s';", user);
mysql_query(conn, query);
}
else {
sendbuff[0] = 'n';sendbuff[1] = '\0';
}
mysql_free_result(res);
write(sockfd, sendbuff, strlen(sendbuff));
//printf("sendbuff> '%s'
", sendbuff);
sql_exit(conn);
printf("login user=%s passwd=%s
", user, passwd);
}
/*
* get user online notice and update online time to 12
*/
void user_at()
{
MYSQL *conn = sql_init();
int i;
char user[21];
for (i=2; i<recv_len; ++i) {
user[i-2] = recvbuff[i];
}
user[recv_len-2] = '\0';
char query[107];
sprintf(query, \
"update jchat.user set online_time=12 where user='%s';", \
user);
mysql_query(conn, query);
sql_exit(conn);
//printf("%s is online
", user);
}
/*
* return a user's unread message
* and delete the message in mysql
*/
void get_mesg(int sockfd)
{
MYSQL *conn = sql_init();
int i;
char user[21];
for (i=2; i<recv_len; ++i) {
user[i-2] = recvbuff[i];
}
user[recv_len-2] = '\0';
char query[107];
sprintf(query, \
"select * from jchat.user where \
user='%s';", user);
mysql_query(conn, query);
MYSQL_RES *res = mysql_use_result(conn);
MYSQL_ROW row = mysql_fetch_row(res);
if (row != NULL) { // user exist
mysql_free_result(res);
sprintf(query, \
"select * from jchat.mesg where recvuser='%s';", \
user);
mysql_query(conn, query);
char senduser[30], recvuser[30], text[1007];
res = mysql_use_result(conn);
sendbuff[0] = '\0';
int hasMesg = 0;
while ((row = mysql_fetch_row(res)) != NULL) {
hasMesg = 1;
int row_num = mysql_num_fields(res);
strcpy(senduser, row[0]);
strcpy(recvuser, row[1]);
strcpy(text, row[2]);
strcat(sendbuff, senduser);
strcat(sendbuff, ":" );
strcat(sendbuff, text );
strcat(sendbuff, ";" );
}
if (!hasMesg) {
strcpy(sendbuff, ";");
}
mysql_free_result(res);
sprintf(query, \
"delete from jchat.mesg where recvuser='%s';", \
user);
mysql_query(conn, query);
write(sockfd, sendbuff, strlen(sendbuff));
//printf("get_mesg sendbuff> '%s'
", sendbuff);
}
sql_exit(conn);
//printf("%s get message from server
", user);
}
/*
* one user send message to another user
* store to mysql
*/
void send_mesg()
{
MYSQL *conn = sql_init();
int i, j, k, x;
i = 2;j = 3;
while (recvbuff[j] != ':') ++j;
++j;
k = j + 1;
while (recvbuff[k] != ':') ++k;
++k;
//printf("i=%d, j=%d, k=%d
",i,j,k);
char senduser[30], recvuser[30], text[1007];
for (x=0; x<j-1-i; ++x) {
senduser[x] = recvbuff[x+i];
}
senduser[j-1-i] = '\0';
for (x=0; x<k-1-j; ++x) {
recvuser[x] = recvbuff[x+j];
}
recvuser[k-1-j] = '\0';
for (x=0; x<recv_len-k; ++x) {
text[x] = recvbuff[x+k];
}
text[recv_len-k] = '\0';
//printf("senduser = '%s'
recvuser = '%s'
", senduser, recvuser);
int user_exist = 1;
char query[107];
sprintf(query, \
"select * from jchat.user where user='%s';", \
senduser);
mysql_query(conn, query);
MYSQL_RES *res = mysql_use_result(conn);
MYSQL_ROW row = mysql_fetch_row(res);
if (row == NULL) { // send user not exist
user_exist = 0;
}
mysql_free_result(res);
sprintf(query, \
"select * from jchat.user where user='%s';", \
recvuser);
mysql_query(conn, query);
res = mysql_use_result(conn);
row = mysql_fetch_row(res);
if (row == NULL) { // recv user not exist
user_exist = 0;
}
mysql_free_result(res);
if (user_exist) {
sprintf(query, \
"insert into jchat.mesg values('%s','%s','%s');", \
senduser, recvuser, text);
mysql_query(conn, query);
}
sql_exit(conn);
printf("%s send message to %s
", senduser, recvuser);
}
/*
* return current online users
*/
void online_user(int sockfd)
{
MYSQL *conn = sql_init();
mysql_query(conn, "select user from jchat.user where online_time>0;");
sendbuff[0] = '\0';
MYSQL_RES *res = mysql_use_result(conn);
MYSQL_ROW row;
int hasOnline = 0;
while ((row = mysql_fetch_row(res)) != NULL) {
hasOnline = 1;
strcat(sendbuff, row[0]);
strcat(sendbuff, ";" );
}
if (!hasOnline) {
strcpy(sendbuff, ";");
}
mysql_free_result(res);
write(sockfd, sendbuff, strlen(sendbuff));
//printf("online_user sendbuff> '%s'
", sendbuff);
sql_exit(conn);
}
/*
* user quit
* update online time to 0
*/
void quit()
{
MYSQL *conn = sql_init();
int i;
char user[21];
for (i=2; i<recv_len; ++i) {
user[i-2] = recvbuff[i];
}
user[recv_len-2] = '\0';
char query[107];
sprintf(query, \
"update jchat.user set online_time=0 where user='%s';", \
user);
mysql_query(conn, query);
printf("%s quit
", user);
sql_exit(conn);
exit(0); // exit this process
}
void process(int sockfd)
{
while ((recv_len = read(sockfd, recvbuff, MAXLINE)) > 0) {
recvbuff[recv_len] = '\0';
//printf("process recvbuff> '%s'
", recvbuff);
switch (recvbuff[0]) {
case 'r': // regist
regist(sockfd);
break;
case 'l': // login
login(sockfd);
break;
case 'a': // online notice
user_at();
break;
case 'g': // get message
get_mesg(sockfd);
break;
case 's': // send message
send_mesg();
break;
case 'o': // online user check
online_user(sockfd);
break;
case 'q': // quit
quit();
break;
}
}
}
process.h:
/*server/process.h*/
#ifndef PROCESS_H
#define PROCESS_H
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
/*
* refresh online user's online time every minute
* seemed as offline if online time decrease to 0
*/
void refresh_online_time();
/*
* process different command from client
*/
void process(int sockfd);
#endif // PROCESS_H
sql.c:mysqlの新しい接続
/*server/sql.h*/
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include "sql.h"
static char *host_name = "localhost";
static char *user_name = "your mysql user"; // mysql
static char *passwd = "your mysql password";
static unsigned int port_num = 0;
static char *socket_name = NULL;
static char *db_name = "jchat";
static unsigned int flags = 0;
MYSQL *sql_init()
{
MYSQL *conn;
MY_INIT("jchat_server");
if (mysql_library_init(0,NULL,NULL)) {
fprintf(stderr, "mysql_library_init() failed
");
return NULL;
}
conn = mysql_init(NULL);
if (conn == NULL) {
fprintf(stderr, "mysql_init() failed
");
return NULL;
}
if (mysql_real_connect(conn,host_name,user_name,passwd,
db_name,port_num,socket_name,flags) == NULL) {
fprintf(stderr, "mysql_real_connect() failed
");
mysql_close(conn);
return NULL;
}
return conn;
}
void sql_exit(MYSQL *conn)
{
mysql_close(conn);
mysql_library_end();
}
sql.h:
/*server/sql.h*/
#ifndef SQL_H
#define SQL_H
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
/*
* link to mysql
* return 1 if succeed, 0 if fail
*/
MYSQL *sql_init();
void sql_exit(MYSQL *conn);
#endif // SQL_H