2014-02-19 27 views
1

我正在編寫一個連接到服務器的程序,獲取發送的數據並將其顯示到屏幕上。我正在爲使用ncurses的程序創建UI。我初始化屏幕,連接到服務器,讀取套接字,打印輸出,關閉套接字,結束屏幕,這給我一個分段錯誤。在C中,爲什麼從套接字讀取會導致printw給出分段錯誤?

如果我跳過插座讀取,沒有錯誤發生,並顯示屏幕;但是,顯示之前有一段暫停。我想知道它是否與我的套接字是非阻塞的事實有關?

我有3個文件,main.csocket.cscreen.c。我將截斷所需信息的文件。

的main.c

#include "socket.h" 
#include "screen.h" 

int main(int argc, char *argv[]){ 
    screenInit(); 

    socketConnect(argv[1], argv[2]); 
    sleep(1); 

    char buffer[1024]; 
    socketRead(buffer, sizeof buffer);//commenting this out lets the screen display 
    screenDraw(buffer); 

    socketClose(); 
    screenEnd(); 

    return 0; 
} 

socket.c中

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <fcntl.h> 

int sockfd; 

int socketRead(char *output, int length){ 
    memset(output, 0, length); 

    char buffer[1024]; 
    memset(buffer, 0, sizeof buffer); 

    for(;;){ 
    char *ch; 

    if(recv(sockfd, ch, 1, 0) == -1) 
     return -1; 

    if(strlen(buffer)+1 == sizeof buffer) 
     return -2; 

    strcat(buffer, ch); 
    if(*ch == '\n'){ 
     if(strlen(buffer)+1 <= length){ 
     strcpy(output, buffer); 
     return 0; 
     }else{ 
     return -3; 
     } 
    } 
    } 
} 

int socketConnect(char *host, char *port){ 
    //sockfd gets set here 
    fcntl(sockfd, F_SETFL, O_NONBLOCK); 
    return 0; 
} 

void socketClose(){ 
    close(sockfd); 
} 

screen.c

#include <ncurses.h> 

void screenInit(){ 
    initscr(); 
    cbreak(); 
    noecho(); 
} 

void screenDraw(char *string){ 
    printw("%s", string); 
    refresh(); 
    getch(); 
} 

void screenEnd(){ 
    endwin(); 
} 

下面是堆棧

#0 0x00007ffff7647caa in ??() from /lib/x86_64-linux-gnu/libc.so.6 
#1 0x00007ffff7649191 in ??() from /lib/x86_64-linux-gnu/libc.so.6 
#2 0x00007ffff764b580 in malloc() from /lib/x86_64-linux-gnu/libc.so.6 
#3 0x00007ffff7bce2de in _nc_printf_string() from /lib/x86_64-linux-gnu/libncurses.so.5 
#4 0x00007ffff7bc93ef in vwprintw() from /lib/x86_64-linux-gnu/libncurses.so.5 
#5 0x00007ffff7bca0e9 in printw() from /lib/x86_64-linux-gnu/libncurses.so.5 
#6 0x000000000040111f in screenDraw() 
#7 0x0000000000400d56 in main() 

我想我在這裏添加我的Makefile以及如果由於某種原因,有一些東西做的問題。

的Makefile

objects = main.o socket.o screen.o 

program: $(objects) 
    cc -Wall -o program $(objects) -lncurses 

.PHONY: clean 
clean: 
    @-rm -f program 

回答

1

您有一個錯誤在這裏socketRead()

char *ch; 

if(recv(sockfd, ch, 1, 0) == -1) 
    return -1; 

ch只是一個指針,未分配的內存來存儲東西在裏面 - 你必須是未初始化的指針。您不能使用它並將其傳遞到recv,因爲recv將嘗試寫入未定義的位置。這就是爲什麼你的程序崩潰。

我想你想在這裏使用buffer

if (recv(sockfd, buffer, sizeof buffer, 0) == -1) { ... } 

,或者,你可以ch點的有效位置使用它之前:

ch = buffer; 
if (recv(sockfd, ch, sizeof buffer, 0) == -1) { ... } 

但是請注意,在這種情況下,您不能使用sizeof ch,因爲這會產生char *的大小。

如果你想明確地留出的空間用於空終止字節,然後使用sizeof(buffer) - 1

if (recv(sockfd, buffer, sizeof buffer, 0) == -1) { ... } 

這些線路也錯了,因爲同一個理由:你從來沒有初始化ch

strcat(buffer, ch); 
if (*ch == '\n') { 

請注意recv(sockfd, buffer, sizeof(buffer)-1, 0)將讀取至多sizeof(buffer)-1字節的塊。你的代碼表達了你想通過char來讀取它的想法;在這種情況下,您可能想要使ch代替char *。在這種情況下,你只需要在調用recv使用運營商的地址,因爲recv需要一個指向:

if (recv(sockfd, &ch, 1, 0) == -1) 

但隨後的過程中,你不能用一個char使用strcatstrcat預計空終止字符序列),而不是if (*ch == '\n'),您必須使用if (ch == '\n')

+0

是的,你最新的編輯是完全正確的。我想閱讀,直到我到一個換行。所以我做了這些改變,但我怎麼能追加char到緩衝區沒有strcat? NVM。快速谷歌搜索有很多答案。謝謝您的幫助。 =) – Aust

+0

@還好你知道了。對不起我的沉默,不得不突然離開。 –

0

的字符指針將不會被初始化到緩衝區:還需要

char *ch = buffer; 
if(recv(sockfd, ch, 1, 0) == -1) 
    return -1; 

錯誤處理來讀取SocketRead()的返回碼 - 也許你留下了爲了簡潔起見,請勿出於您的帖子。

相關問題