我正在使用C中的ncurses UI开发一个简单的聊天程序,并且遇到了这个奇怪的问题。
过程如下:
服务器等待客户端连接。
连接客户端后,服务器会提示输入用户名。
在接收到用户名之后,服务器开始侦听来自客户端的消息。
每个时间服务器收到一条消息,它将其与用户名连接起来,并将其广播给所有客户端,因此客户端收到的消息应如下所示:
username: text
这是出问题的地方。
客户端输出:
test^U^D: hello waddup
因此,基本上,如果用户名少于6个字母,则接收到的数组的前六个索引总是填充有这些转义字符,这些转义字符打印在客户端上。
像这样:
USERNAME: a //user input
YOU: test message a^C^\^?^U^D: test message
在调查此问题时,我已在服务器端添加了调试消息。
服务器输出:
USERNAME RECEIVED:
: message
//tested one-letter username - q
USERNAME RECEIVED: q
q: asd
//two-letter - qw
USERNAME RECEIVED: as
as: sdf
//three-letter - asd. Still doesn't print the last letter, eventhough on client side it is printed, probably some stupid mistake I've made and didn't notice yet
USERNAME RECEIVED: test
test: hello
//Finally prints full u-name. No escape characters like on client side.
//If u-name >= 4 let. it is displayed normally on server side. If uname >= 6 -- on client side
我的猜测是该问题出现在套接字层上,但我不是 套接字编程方面的知识渊博,对我的建议充满信心。
或者,该问题可能与ncurses用户界面有关,因为它在客户端(使用ncurses)可见,而在服务器端(将调试消息打印到sdout)不可见。
我知道它可能确实很杂乱且效率低下,但是这个项目是我的第一个相对认真的C项目,我肯定以后会重构和优化此代码。
服务器端有问题的功能代码:
void transmitt(int socket, int index){
printf("CONNECTION TO THREAD %x\n", pthread_self());
char tmp[MAX];
char bye[MAX];
char uname[MAX_UNAME];
char buffer[MAX+MAX_UNAME];
sprintf(bye, "%d", BYE_MESSAGE);
recv_uname(socket, uname);
while(1){
bzero(tmp, sizeof(tmp));
bzero(buffer, sizeof(buffer));
recv(socket, tmp, sizeof(tmp), 0);
if(strncmp(bye, tmp, MAX) == 0){
printf("THREAD: %x DISCONNECTED\n", pthread_self());
snprintf(buffer, sizeof(buffer), "SERVER MESSAGE: %s HAS DISCONNECTED", uname);
for(int i =0;i<MAX_CLIENTS;i++){
if(clients[i] != NULL){
send(clients[i], buffer, sizeof(buffer), 0);
}
}
clients[index] = NULL;
return;
}
snprintf(buffer, sizeof(buffer), "%s: %s", uname, tmp);
for(int i =0;i<MAX_CLIENTS;i++){
if(clients[i] != NULL){
send(clients[i], buffer, sizeof(buffer), 0);
}
}
printf("%s\n", buffer);
}
}
void recv_uname(int socket, char* uname){
char prompt[MAX_UNAME];
snprintf(prompt, sizeof(prompt), "USERNAME: ");
send(socket, prompt, sizeof(prompt), 0);
recv(socket, uname, MAX_UNAME, 0);
printf("USERNAME RECEIVED: %s\n", uname);
}
客户端:
void chat_loop(int socket){
char buff[MAX], sbuff[MAX+MAX_UNAME];
char tmp;
int n, y=0, x=0, maxcol, maxrow, recy, recx;
getmaxyx(stdscr, maxrow, maxcol);
recy = 0;
recx = maxcol/2;
timeout(1);
bzero(buff, sizeof(buff));
printw("YOU: ");
n=0;
while(1){
tmp = getch();
getyx(stdscr, y, x);
if(tmp == '`'){
sprintf(buff, "%d", BYE_MESSAGE);
send(socket, buff, sizeof(buff), 0);
return;
}
else if(tmp == '\n'){
send(socket, buff, sizeof(buff), 0);
bzero(buff, sizeof(buff));
// printw("YOU: ");
move(++y, 0);
n=0;
}
else if(tmp == ALT_BACKSPACE){
if(x > 0){
mvdelch(y, x-1);
buff[--n] = NULL;
}
}
else if(tmp != ERR){
printw("%c", tmp);
buff[n++] = tmp;
}
bzero(sbuff, sizeof(sbuff));
recv(socket, sbuff, sizeof(sbuff), MSG_DONTWAIT);
if(check_buff(sbuff, sizeof(sbuff)) == 0){
getyx(stdscr, y, x);
move(recy++, recx);
printw("%s", sbuff);
move(y, x);
}
refresh();
}
}
void send_uname(int socket){
char buff[MAX], unbuff[MAX_UNAME];
char tmp;
int n=0, y=0, x=0, init_x;
bzero(buff, sizeof(buff));
recv(socket, buff, sizeof(buff), 0);
printw("%s", buff);
getyx(stdscr, y, init_x);
while((tmp = getch())!='\n'){
getyx(stdscr, y, x);
if(tmp == ALT_BACKSPACE){
if(x > init_x){
mvdelch(y, x-1);
unbuff[--n] = NULL;
}
}
else if(tmp != ERR){
if(n < MAX_UNAME){
printw("%c", tmp);
unbuff[n++] = tmp;
}
}
refresh();
}
printw("\n");
send(socket, unbuff, sizeof(unbuff), 0);
}
int check_buff(char* buffer, size_t n){
for(int i=0;i<n;i++){
if(buffer[i]!=NULL)
return 0;
}
return -1;
}
常量,包括:
#include<stdio.h>
#include<stdlib.h>
#include <netdb.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<ncurses.h>
//common
#define ALT_BACKSPACE 127
#define MAX 128 //common buffer size
#define MAX_UNAME 24
#define BYE_MESSAGE 10101010
//server-specific
#define MAX_THREADS 4
#define MAX_CLIENTS 4
这就是我所拥有的。