Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
NCurses聊天行为不正常,在select中被阻止_C_Sockets_Select_Networking_Ncurses - Fatal编程技术网

NCurses聊天行为不正常,在select中被阻止

NCurses聊天行为不正常,在select中被阻止,c,sockets,select,networking,ncurses,C,Sockets,Select,Networking,Ncurses,我为一个社交网络和一个简单的聊天室编写了一个C应用程序。我使用了网络课程、插座和基本的网络工具 问题是,我的函数使用select()读取服务器套接字和stdin,因此当我开始编写消息时,输出窗口将冻结,并且仅在我按enter键后显示来自其他客户端的消息 我尽了一切可能。。有办法解决这个问题吗 我还尝试强制nocbreak()。它可以正常工作,但如果我这样做,当我编写消息时,回音将被禁用,并且在我键入时,输入窗口中不会显示任何内容,即使消息在那里,但类似于“不可见” 代码如下: ssize_t s

我为一个社交网络和一个简单的聊天室编写了一个C应用程序。我使用了网络课程、插座和基本的网络工具

问题是,我的函数使用select()读取服务器套接字和stdin,因此当我开始编写消息时,输出窗口将冻结,并且仅在我按enter键后显示来自其他客户端的消息

我尽了一切可能。。有办法解决这个问题吗

我还尝试强制nocbreak()。它可以正常工作,但如果我这样做,当我编写消息时,回音将被禁用,并且在我键入时,输入窗口中不会显示任何内容,即使消息在那里,但类似于“不可见”

代码如下:

ssize_t safePrefRead(int sock, void *buffer)
{
    size_t length = strlen(buffer);

    ssize_t nbytesR = read(sock, &length, sizeof(size_t));
    if (nbytesR == -1)
    {
        perror("read() error for length ! Exiting !\n");
        exit(EXIT_FAILURE);
    }

    nbytesR = read(sock, buffer, length);
    if (nbytesR == -1)
    {
        perror("read() error for data ! Exiting !\n");
        exit(EXIT_FAILURE);
    }

    return nbytesR;
}

ssize_t safePrefWrite(int sock, const void *buffer)
{
    size_t length = strlen(buffer);

    ssize_t nbytesW = write(sock, &length, sizeof(size_t));
    if (nbytesW == -1)
    {
        perror("write() error for length ! Exiting !\n");
        exit(EXIT_FAILURE);
    }

    nbytesW = write(sock, buffer, length);
    if (nbytesW == -1)
    {
        perror("write() error for data ! Exiting !\n");
        exit(EXIT_FAILURE);
    }

    return nbytesW;
}

void activeChat(int sC, const char *currentUser, const char *room)
{
    char inMesg[513], outMesg[513];
    char user[33];


    int winrows, wincols;
    WINDOW *winput, *woutput;

    initscr();
    nocbreak();
    getmaxyx(stdscr, winrows, wincols);
    winput = newwin(1, wincols, winrows - 1, 0);
    woutput = newwin(winrows - 1, wincols, 0, 0);
    keypad(winput, true);
    scrollok(woutput, true);
    wrefresh(woutput);
    wrefresh(winput);



    fd_set all;
    fd_set read_fds;
    FD_ZERO(&all);
    FD_ZERO(&read_fds);
    FD_SET(0, &all);
    FD_SET(sC, &all);

    wprintw(woutput, "Welcome to room '%s' \n Use /quitChat to exit !\n!", room);
    wrefresh(woutput);

    while (true)
    {
        memcpy( &read_fds, &all, sizeof read_fds );
        if (select(sC + 1, &read_fds, NULL, NULL, NULL) == -1)
        {
            perror("select() error or forced exit !\n");
            break;
        }

        if (FD_ISSET(sC, &read_fds))
        {
            memset(inMesg, 0, 513);
            safePrefRead(sC, user);
            safePrefRead(sC, inMesg);
            wprintw(woutput, "%s : %s\n", user, inMesg);
            wrefresh(woutput);
            wrefresh(winput);
        }

        if (FD_ISSET(0, &read_fds))
        {

            //wgetnstr(winput, "%s", outMesg);

            int a, i = 0;

            while ( i < MAX_BUF_LEN && (a = wgetch(winput)) != '\n')
            {
                outMesg[i] = (char)a;
                i++;
            }
            outMesg[i] = 0;


            if (outMesg[0] == 0)
                continue;
            if (strcmp(outMesg, "/quitChat") == 0)
            {
                safePrefWrite(sC, outMesg);
                break;
            }
            safePrefWrite(sC, outMesg);
            delwin(winput);
            winput = newwin(1, wincols, winrows - 1, 0);
            keypad(winput, true);
            wrefresh(winput);
        }
    }

    delwin(winput);
    delwin(woutput);
    endwin();
}
ssize\t安全预读(int-sock,void*buffer)
{
大小\u t长度=strlen(缓冲区);
ssize_t nbytesR=read(sock,&length,sizeof(size_t));
如果(nbytesR==-1)
{
perror(“读取()长度错误!正在退出!\n”);
退出(退出失败);
}
nbytesR=读取(sock、缓冲区、长度);
如果(nbytesR==-1)
{
perror(“数据读取()错误!正在退出!\n”);
退出(退出失败);
}
返回nbytesR;
}
ssize\u t safeprewrite(int sock,const void*缓冲区)
{
大小\u t长度=strlen(缓冲区);
ssize_t nbytesW=写入(sock,&length,sizeof(size_t));
如果(nbytesW==-1)
{
perror(“写入()长度错误!正在退出!\n”);
退出(退出失败);
}
nbytesW=写入(sock、缓冲区、长度);
如果(nbytesW==-1)
{
perror(“数据写入()错误!正在退出!\n”);
退出(退出失败);
}
返回nbytesW;
}
void activeChat(int sC,const char*currentUser,const char*room)
{
char inMesg[513],outMesg[513];
字符用户[33];
int winrows,wincols;
窗口*winput,*woutput;
initscr();
nocbreak();
getmaxyx(stdscr、winrows、wincols);
winput=newwin(1,wincols,winrows-1,0);
woutput=newwin(winrows-1,wincols,0,0);
键盘(winput,真);
scrollok(woutput,true);
鲜活(woutput);
wrefresh(winput);
fd_设置全部;
fd_设置读取_fds;
FD_零和全部;
FD_零(&read_fds);
FD_集(0和全部);
FD_集(sC和全部);
wprintw(woutput,“欢迎来到房间'%s'\n使用/quitChat退出!\n!”,房间);
鲜活(woutput);
while(true)
{
memcpy(&read_fds,&all,read_fds的大小);
如果(选择(sC+1,&read_fds,NULL,NULL,NULL)=-1)
{
perror(“选择()错误或强制退出!\n”);
打破
}
if(FD_ISSET(sC和读取fds))
{
memset(inMesg,0513);
安全预读(sC,用户);
安全预读(sC、inMesg);
wprintw(输出,“%s:%s\n”,用户,inMesg);
鲜活(woutput);
wrefresh(winput);
}
if(FD_-ISSET(0,读取&u-fds))
{
//wgetnstr(winput,“%s”,outMesg);
int a,i=0;
而(i
-safePrefWrite和safePrefRead是用于预处理读/写和错误处理的包装器 -sC是服务器套接字

乐:我试过用叉子和线。使用fork的行为与此相同,线程是一场灾难,终端被弄糟了

谢谢。

修改
while(true)
循环,一次只处理stdin的一个字符

对于stdin,这主要意味着读取单个字符:

如果char为'\n',则按当前方式处理

否则,只需将char追加到缓冲区进行写入

通常,在向缓冲区添加字符进行写入之前,请检查缓冲区是否已满

添加代码以处理要写入的缓冲区已满的情况

按以下顺序结束函数:

delwin(winput);
delwin(woutput);
endwin();
endwin();
结束两个窗口

在处理套接字输入期间不要调用endwin()

select()
返回错误条件时,不要调用endwin()

在C语言中,
fd_集合
不是一个固有的大小,因此使用
memcpy()
进行设置
all
读取。建议:

memcpy( &read_fds, &all, sizeof read_fds );
while ( i < MAX_BUF_LEN && (a = wgetch(winput)) != '\n')
参数:
currentUser
未使用,建议插入行:

 (void)currentUser;
消除编译器警告消息

为了便于阅读和理解,建议#使用有意义的名称定义魔法数字513和33,然后在整个代码中使用这些有意义的名称

#define MAX_BUF_LEN (513)
#define MAX_USER_LEN (33)  
此行:
outMesg[i]=a引发编译器警告,建议:

outMesg[i] = (char)a;
while ( i < MAX_BUF_LEN && (a = wgetch(winput)) != '\n')
此行:
while((a=wgetch(winput))!='\n')
会允许缓冲区溢出[],导致未定义的行为,并可能导致seg故障事件。建议:

while ( i < MAX_BUF_LEN && (a = wgetch(winput)) != '\n')

正如@user3629249所指出的,有几个批评可以应用于示例代码。然而,这些改进并没有解决OP的问题

OP似乎忽略了这些功能:

  • 或者,使
    wgetch
    读取未缓冲的数据,即不等待
    '\n'
  • 或者,控制等待输入的时间量

顺便说一句,让
select
与curses程序一起工作会对curses库的内部行为做出假设:让它可靠地工作可能会很麻烦。

最后只使用大循环就解决了这个问题

如果将来有人遇到同样的问题,下面是代码: