当收到消息时,几次收到同一个消息,有时就会崩溃,当首位是空格也会崩溃,和字数无关,短的和长的都有可能发生
如下日志
~/libws $ ./lw
[2024/06/09 14:17:34:1563] N: lws_create_context: LWS: 4.3.3-no_hash, NET CLI SRV H1 H2 WS ConMon IPv6-absent
[2024/06/09 14:17:34:1574] N: __lws_lc_tag: ++ [wsi|0|pipe] (1)
[2024/06/09 14:17:34:1575] N: __lws_lc_tag: ++ [vh|0|default||7681] (1)
[2024/06/09 14:17:34:1577] N: [vh|0|default||7681]: lws_socket_bind: source ads 0.0.0.0
[2024/06/09 14:17:34:1577] N: __lws_lc_tag: ++ [wsi|1|listen|default||7681] (2)
Starting server...
[2024/06/09 14:17:37:5358] N: __lws_lc_tag: ++ [wsisrv|0|adopted] (1)
Connection established
Received msg: login admin 5431
Login successful for user: admin
User admin logged in
无法打开留言板文件: No such file or directory
//此处正常,因为没有留言程序能够正常处理
0xf0532700Received msg: sent admin ssjii sjaja sjsk .njj
Received msg: sent admin jdiajb shshsba sbajs
Received msg: sent admin ssjii sjaja sjsk .njj
Received msg: sent admin ssjii sjaja sjsk .njj
Segmentation fault
Program received signal SIGSEGV, Segmentation fault.
0xf777c5c0 in je_large_dalloc ()
from /apex/com.android.runtime/lib/bionic/libc.so
(gdb) bt
#0 0xf777c5c0 in je_large_dalloc ()
from /apex/com.android.runtime/lib/bionic/libc.so
#1 0xf77620a4 in je_free ()
from /apex/com.android.runtime/lib/bionic/libc.so
#2 0x004034cc in callback (wsi=0xf791c700,
reason=LWS_CALLBACK_RECEIVE, user=0x0, in=0xf7cbf4e0, len=1910)
at main.c:597
#3 0xf789d7c2 in ?? ()
from /data/data/com.termux/files/usr/lib/libwebsockets.so
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) info registers
r0 0x686c6 427718
r1 0x0 0
r2 0x0 0
r3 0x0 0
r4 0xf7b7a008 4156006408
r5 0xf 15
r6 0x0 0
r7 0x0 0
r8 0xf77e925c 4152267356
r9 0xf7c00000 4156555264
r10 0xf7b7a0a4 4156006564
r11 0xf7cbf4e0 4157338848
r12 0xf77e4ec8 4152250056
sp 0xfffee8d0 0xfffee8d0
lr 0xf77620a5 -143253339
pc 0xf777c5c0 0xf777c5c0 <je_large_dalloc+32>
cpsr 0x60010030 1610678320
fpscr 0x80000000 -2147483648
tpidruro <unavailable>
(gdb) frame
#0 0xf777c5c0 in je_large_dalloc ()
from /apex/com.android.runtime/lib/bionic/libc.so
如下代码
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_USERNAME_LENGTH 256
#define MAX_PASSWORD_LENGTH 256
#define MAX_CLIENTS 64
#define MAX_LEN 8192
#define de puts("part");getchar();
typedef struct client_info
{
struct lws *wsi; // WebSocket连接指针
char username[MAX_USERNAME_LENGTH]; // 用户名
} client_info_t;
// 客户端数组
client_info_t clients[MAX_USERNAME_LENGTH] = { 0 };
int num_clients = 0;
int
send_to_client_by_username (const char *comeusername, const char *username,const char *message, int length);
int
is_wsi_in_clients (struct lws *wsi)
{
for (int i = 0; i < num_clients; i++)
{
if (clients[i].wsi == wsi)
{
// 找到了匹配的wsi,它存在于数组中
return 1;
}
}
// 没有找到匹配的wsi,它不存在于数组中
return 0;
}
//FILE IO FUC**********************************
int count_characters(const char *filename, FILE *file) {
int count = 0;
if(file==NULL){
if(filename){
file = fopen(filename, "r");
}
}
if (file == NULL) {
perror("Error opening file");
return -1;
}
int ch;
while ((ch = fgetc(file)) != EOF) {
count++;
}
fclose(file);
return count;
}
int
count_lines_with_string (const char *filename, const char *str)
{
char *line = NULL; // 动态分配每行内容
size_t linecap = 0; // 保存当前分配的容量
int count = 0;
FILE *file = fopen (filename, "r");
if (file == NULL)
{
perror ("打开文件时出错");
return -1;
}
while (getline (&line, &linecap, file) != -1)
{
// 删除行尾的换行符
size_t len = strlen (line);
if (len > 0 && line[len - 1] == '\n')
{
line[len - 1] = '\0';
}
if (strstr (line, str) != NULL)
{
count++;
}
}
if (ferror (file))
{
perror ("读取文件时出错");
fclose (file);
free (line); // 释放分配的内存
return -1;
}
fclose (file);
free (line); // 释放分配的内存
return count;
}
/***/
void append_message_if_user_exists(const char *username, const char *msg) {
// 检查usr.ini中是否存在username
//if (count_lines_with_string("usr.ini", username) > 0) {
// 构造leave.ini文件名
char leave_file[256];
snprintf(leave_file, sizeof(leave_file), "%sleave.ini", username);
// 以追加模式打开文件
FILE *file = fopen(leave_file, "a");
if (file == NULL) {
perror("无法打开文件");
return;
}
// 追加msg并换行
fprintf(file, "%s\n", msg);
fclose(file);
//}
}
// 函数:删除文件的指定行
int
delete_line (const char *filename, int line_to_delete)
{
// 创建临时文件名
char temp_filename[300];
strcpy (temp_filename, filename);
strcat (temp_filename, ".tmp");
// 打开源文件和临时文件
FILE *source = fopen (filename, "r");
FILE *temp = fopen (temp_filename, "w");
if (source == NULL || temp == NULL)
{
perror ("Error opening file(s)");
return -1;
}
// 行计数器
int line_counter = 0;
char buffer[1024];
// 读取并处理每一行
while (fgets (buffer, sizeof (buffer), source))
{
// 如果当前行不是要删除的行,则写入临时文件
if (line_counter != line_to_delete)
{
fputs (buffer, temp);
}
line_counter++;
}
// 关闭文件
fclose (source);
fclose (temp);
// 删除原始文件
remove (filename);
// 将临时文件重命名为原始文件名
if (rename (temp_filename, filename) != 0)
{
perror ("Error renaming file");
return -1;
}
puts ("更新成功");
return 0;
}
//FILE IO FUC OVER---------------
//InteractIve IO FUC************************************
void handle_message_board(const char *username) {
// 构造留言板文件名
char message_board_file[300];
snprintf(message_board_file, sizeof(message_board_file), "%sleave.ini", username);
char message_history_file[300];
snprintf(message_history_file, sizeof(message_history_file), "%shistory.ini", username);
// 打开留言板文件
FILE *history = fopen(message_history_file, "a");
if (history == NULL) {
perror("无法打开历史文件");
return;
}
FILE *file = fopen(message_board_file, "r");
if (file == NULL) {
fclose(history);
perror("无法打开留言板文件");
return;
}
// 发送"留言记录"消息
const char *start_msg = "留言记录";
send_to_client_by_username (NULL, username, start_msg, strlen(start_msg));
fprintf(history,"%s\n",start_msg);
fflush(history);
// 读取并发送留言板内容
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, file)) != -1) {
// 去除换行符
line[strcspn(line, "\n")] = 0;
// 发送当前行
send_to_client_by_username (NULL, username, line, strlen(line));
fprintf(history,"%s\n",line);
fflush(history);
}
// 发送"留言完毕"消息
const char *end_msg = "留言完毕";
send_to_client_by_username (NULL, username, end_msg, strlen(end_msg));
fprintf(history,"%s\n",end_msg);
fflush(history);
// 清理资源
fclose(file);
fclose(history);
if (line) {
free(line);
}
// 删除留言板文件
if (remove(message_board_file) != 0) {
perror("无法删除留言板文件");
}
}
// 发送函数
int
send_to_client_by_username (const char *comeusername, const char *username,const char *message, int length)
{
char *combined;
// 分配足够的空间来存放合并后的字符串
size_t combined_length = strlen (username) + strlen (message) + 2; // 加2是为了包括':'和'\0'
combined = (char *) malloc (combined_length * sizeof (char));
if (combined == NULL)
{
// 分配内存失败
fprintf (stderr, "Memory allocation failed\n");
return 1;
}
// 使用sprintf来格式化字符串
if(comeusername){
sprintf (combined, "%s:%s", comeusername, message);
}else{
sprintf (combined, "%s", message);
}
for (int i = 0; i < num_clients; i++)
{
if (strcmp (clients[i].username, username) == 0)
{
// 找到匹配的用户名,发送消息
lws_write (clients[i].wsi, (unsigned char *) combined,
strlen (combined), LWS_WRITE_TEXT);
free (combined);
return 0;
}
}
// 没有找到匹配的用户名
free (combined);
return -1;
}
/***/
int
sentToFriend (const char *username, const char *toUsername,
const char *message, int length)
{
char filename[300];
snprintf (filename, sizeof (filename), "%sfriend.ini", toUsername);
if (count_lines_with_string (filename, username) > 0)
{
if (send_to_client_by_username (username, toUsername, message, length)
== 0)
{
return 0;
}
else if (count_lines_with_string ("usr.ini", toUsername) > 0)
{
return 1;
}
}
else
{
return -1;
}
return -1;
}
/***/
int
handle_login (struct lws *wsi, const char *username)
{
if (num_clients >= MAX_CLIENTS)
{
lwsl_err ("Too many clients connected\n");
return -1;
}
// 查找空闲位置存储客户端信息
for (int i = 0; i < MAX_CLIENTS; i++)
{
if (clients[i].wsi == NULL)
{
clients[i].wsi = wsi;
strncpy (clients[i].username, username, MAX_USERNAME_LENGTH - 1);
clients[i].username[MAX_USERNAME_LENGTH - 1] = '\0'; // 确保字符串以null结尾
num_clients++;
printf ("User %s logged in\n", username);
return 0; // 登录成功
}
}
lwsl_err ("No free slot for new client\n");
return -1; // 登录失败
}
char message[] = "用户错误";
//OVER------------------------------
//函数回调**************************************
static int
callback (struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{
switch (reason)
{
//建立回调...................
case LWS_CALLBACK_ESTABLISHED:
printf ("Connection established\n");
break;
//接收消息.....................
case LWS_CALLBACK_RECEIVE:
// printf("Received data: %s\n", (char *)in);
(char *) in;
char *msg = (char *) in;
for (int i = 0; i < strlen(msg); i++) {
if (msg[i] == '\n' || msg[i] == '\r') {
msg[i] = ' ';
}
}
msg[len] = '\0'; // 确保字符串以null终止
printf ("Received msg: %s\n", msg);
/*
登录处理
*/
if (strncasecmp (msg, "login", 5) == 0 && is_wsi_in_clients (wsi) == 0)
{
char *token;
char *username = NULL;
char *password = NULL;
// 获取第一个 token("login")
token = strtok (msg, " ");
if (token == NULL)
return 1;
// 跳过 "login",获取 "username"
token = strtok (NULL, " ");
// 动态分配内存并复制 "username"
if (token == NULL)
return 1;
username = (char *) malloc (strlen (token) + 1);
if (username != NULL&&token)
{
strcpy (username, token);
}
// 获取 "password"
token = strtok (NULL, " ");
if(token==NULL){
return 1;
}
// 动态分配内存并复制 "password"
password = (char *) malloc (strlen (token) + 1);
if (password != NULL)
{
strcpy (password, token);
}
FILE *file = fopen ("usr.ini", "r");
if (!file)
{
perror ("Error opening file");
return 1;
}
char line[512]; // 假设每行最大长度为511个字符
char usernameINI[256];
char passwordINI[256];
int found = 0;
// 逐行读取文件
while (fgets (line, sizeof (line), file))
{
// 去除换行符
line[strcspn (line, "\n")] = 0;
// 使用fscanf读取用户名和密码
if (sscanf (line, "%s %s", usernameINI, passwordINI) == 2)
{
// 比较用户名
if (strcmp (usernameINI, username) == 0)
{
found = 1;
// 比较密码
if (strcmp (passwordINI, password) == 0)
{
printf ("Login successful for user: %s\n",
usernameINI);
if (handle_login (wsi, username) != -1)
{
char err[] = "登录成功";
lws_write (wsi, (unsigned char *) err,
strlen (err), LWS_WRITE_TEXT);
printf("%p",wsi);
handle_message_board(username);
}
else
{
char err[] = "用户过多";
lws_write (wsi, (unsigned char *) err,
strlen (err), LWS_WRITE_TEXT);
lws_close_reason (wsi, LWS_CLOSE_STATUS_NORMAL,
NULL, 0);
lws_context_destroy (lws_get_context (wsi));
}
}
else
{
printf ("Incorrect password for user: %s\n",
usernameINI);
char err[] = "密码错误";
lws_write (wsi, (unsigned char *) err, strlen (err),
LWS_WRITE_TEXT);
}
break;
}
}
}
if (!found)
{
printf ("User not found: %s\n", username);
char err[] = "用户不存在";
lws_write (wsi, (unsigned char *) err, strlen (err),
LWS_WRITE_TEXT);
}
// 关闭文件
fclose (file);
free (username);
free (password);
}
/*
发送给用户
*/
else if (strncasecmp (msg, "sent", 4) == 0 && is_wsi_in_clients (wsi))
{
char *firstSpace = strchr (msg, ' ');
if (firstSpace == NULL)
{
printf ("没有空格找到\n");
return 1;
}
// 跳过第一个空格,指向username
firstSpace++; // 现在firstSpace指向username的第一个字符
// 找到第二个空格的位置
char *secondSpace = strchr (firstSpace, ' ');
if (secondSpace == NULL)
{
printf ("没有第二个空格找到\n");
return 1;
}
// 计算username的长度
int usernameLength = secondSpace - firstSpace;
// 动态分配内存以存储username
char *username = (char *) malloc (usernameLength + 1); // 加1是为了存储'\0'
if (username == NULL)
{
printf ("内存分配失败\n");
return 1;
}
// 复制username
strncpy (username, firstSpace, usernameLength);
username[usernameLength] = '\0'; // 确保字符串以'\0'结尾
// 现在secondSpace指向textmsg的开始,跳过空格
secondSpace++;
// 计算textmsg的长度
int textmsgLength = strlen (secondSpace);
// 动态分配内存以存储textmsg
char *textmsg = (char *) malloc (textmsgLength + 1); // 加1是为了存储'\0'
if (textmsg == NULL)
{
printf ("内存分配失败\n");
free (username); // 在退出前释放已分配的内存
free (secondSpace);
free (firstSpace);
return 1;
}
// 复制textmsg
strncpy (textmsg, secondSpace, textmsgLength);
textmsg[textmsgLength] = '\0'; // 确保字符串以'\0'结尾
for (int i = 0; i < num_clients; i++)
if (clients[i].wsi == wsi)
{
int iee =
sentToFriend (clients[i].username, username, textmsg,
strlen (textmsg));
if (iee == -1)
{
char err[] = "用户不存在或不是你的好友";
lws_write (wsi, (unsigned char *) err, strlen (err),
LWS_WRITE_TEXT);
}
else if (iee == 1)
{
char errs[] = "用户未登录,已尝试留言";
lws_write (wsi, (unsigned char *) errs, strlen (errs),
LWS_WRITE_TEXT);
append_message_if_user_exists(username, textmsg);
}
}
free (username);
free (secondSpace);
free (firstSpace);
}
/*
指令:好友处理
*/
else if (strncasecmp (msg, "friend", 6) == 0 && is_wsi_in_clients (wsi))
{
for (int i = 0; i < num_clients; i++)
{
if (clients[i].wsi == wsi)
{
char *username = clients[i].username;
char *filename;
size_t username_len = strlen (username);
size_t filename_len = username_len + strlen ("friend.ini") + 1; // 加1是为了'\0'终止符
// 动态分配内存
filename = (char *) malloc (filename_len * sizeof (char));
if (filename == NULL)
{
perror ("Memory allocation failed");
return 1;
}
// 拼接文件名
snprintf (filename, filename_len, "%sfriend.ini", username);
// 处理命令
if (strstr (msg, "friend add"))
{
FILE *file = fopen (filename, "a"); // "r+" 模式表示读写模式
if (file == NULL)
{
perror ("Error opening file");
free (filename); // 释放内存
return 1;
}
// 将新的朋友名添加到文件中
char *friend_name = msg + strlen ("friend new ");
fprintf (file, "%s\n", friend_name);
fclose (file);
}
else if (strstr (msg, "friend rm"))
{
char *friend_name = msg + strlen ("friend rm ");
int lin =
count_lines_with_string (filename, friend_name) - 1;
delete_line (filename, lin);
}
// 关闭文件
// 释放内存
free (filename);
}
}
}
free (msg);
//lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
lws_write (wsi, (unsigned char *) message, strlen (message),
LWS_WRITE_TEXT);
break;
case LWS_CALLBACK_CLOSED:
printf ("Connection closed\n");
// 客户端断开连接时,清理客户端信息
for (int i = 0; i < num_clients; i++)
{
if (clients[i].wsi == wsi)
{
memset (&clients[i], 0, sizeof (client_info_t));
num_clients--;
break;
}
}
break;
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] = {
{
"ocp-protocol",
callback,
0,
0,
},
{NULL, NULL, 0, 0} /* End of list */
};
//MAIN FUC
int
main ()
{
struct lws_context_creation_info info;
memset (&info, 0, sizeof (info));
info.port = 7681;
info.iface = NULL;
info.protocols = protocols;
info.ssl_cert_filepath = "./certificate.pem";
info.ssl_private_key_filepath = "./private.key";
info.gid = -1;
info.uid = -1;
info.options = 0;
struct lws_context *context = lws_create_context (&info);
if (context == NULL)
{
printf ("Failed to create context\n");
return 1;
}
printf ("Starting server...\n");
while (1)
{
lws_service (context, 50);
}
lws_context_destroy (context);
return 0;
}