Linux 局域网聊天室程序设计
本文档介绍一种基于 Linux 使用 C 语言实现简单的局域网聊天室的方法,支持消息群发,
历史数据查询,好友列表查看,好友上线下线提醒等功能。聊天界面如下图所示:
下面将按步骤介绍该系统的设计实现,首先在 linux 下创建一个目录,在目录下按顺序
创建几个文件,clientlist.c common.h sock.c main.c Makefile,如下图所示,创建完各文件之后,
依次在文件里面新增相关的代码内容。
1.在 Makefile 文件里面添加如下内容:
CC=gcc
CPROG= chat
BIN = $(CPROG)
OBJS = main.o sock.o clientlist.o
LDFLAGS += -lpthread
CFLAGS = -I.
all: $(BIN)
install:$(BIN)
@true
uninstall:
rm -f $(OBJS) $(BIN)
clean:
rm -f $(OBJS) $(BIN)
$(BIN): $(OBJS)
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) $(CFLAGS_EXTRA) -o $(BIN)
2.在 main.c 文件里面添加如下内容:
#include <stdio.h>
#include <string.h>
#include "common.h"
void main(int argc, char *argv[])
{
if(argc<2) {
LOG("input fmt err!\n");
return ;
}
if(!strcmp(argv[1], "s")) {
svr_start(SERVER_PORT);
}
else if(!strcmp(argv[1], "c")) {
cli_start(argv);
}
}
3. 在 common.h 文件添加如下内容:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <semaphore.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <fcntl.h>
#define MAXCLI 10
#define SERVER_PORT 8080
#define USRNAME_LENGTH 32
#define RGST_INIT 0
#define RGST_OK 1
#define PKG_HEAD 'm'
#define MSG_MODE_LOGIN '0'
#define MSG_MODE_LOGIN_ACK '1'
#define MSG_MODE_SEND '2'
#define MSG_MODE_GET_LIST '3'
#define MSG_MODE_GET_LIST_ACK '4'
#define MSG_MODE_ONLINE '5'
#define MSG_MODE_OFFLINE '6'
#define HISTROY_FILE "h.txt"
struct client_chn_s {
int skfd;
char usrname[USRNAME_LENGTH];
CIRCLEQ_ENTRY(client_chn_s) link;
};
typedef struct client_chn_s client_chn_t;
typedef struct svr {
int listener;
unsigned short port;
}svr_t;
typedef struct cli {
int sockfd;
unsigned char stat;
unsigned char history_enable;
time_t login_timeout;
time_t reconn_timeout;
char usrname[USRNAME_LENGTH];
char ip[48];
unsigned short port;
}cli_t;
typedef struct msg_s {
unsigned char msgtyp;
unsigned char *payload;
int payloadlen;
unsigned char *username;
int username_len;
}msg_t;
4. 在 sock.c 添加如下内容:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdarg.h>
#include "common.h"
cli_t cli;
void LOG(const char *format,...)
{
va_list argptr;
char buffer[2048];
va_start(argptr,format);
vsprintf(buffer,format,argptr);
va_end(argptr);
//printf("%s", buffer);
}
/*
Hex 打印
*/
void dump_buf(char *label, unsigned char *in, int len)
{
int i=0;
LOG("%s:\n", label);
for(i=0;i<len;i++) {
LOG("%02x ", in[i]&0xff);
if(0==(i+1)%16) {
LOG("\n");
}
}
LOG("\n");
}
void get_cur_time(char *timestamp)
{
time_t timep;
struct tm *p, pp;
time(&timep);
localtime_r(&timep, &pp);
p = &pp;
sprintf(timestamp,"<%04d-%02d-%02d %02d:%02d:%02d>",p->tm_year + 1900,
p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
}
void sk_history_record(char *msg)
{
FILE *fp = fopen(HISTROY_FILE, "ab+");
if(!fp) {
LOG("[%s]open %s fail", __func__, HISTROY_FILE);
return 0;
}
fprintf(fp, "%s\r\n", msg);
fclose(fp);
}
int sk_tcp_svr_init(int port)
{
int yes = 1;
struct sockaddr_in svr_addr;
int listenfd = -1;
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
LOG("create socket() fail\n");
return -1;
}
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
LOG("setsockopt() fail!\n");
exit(0);
return -1;
}
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = INADDR_ANY;
svr_addr.sin_port = htons(port);
memset(&(svr_addr.sin_zero), '\0', 8);
if(bind(listenfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr)) == -1)
{
- 1
- 2
前往页