2015-07-08 3 views
1

У меня есть простая программа сокетов, созданная на C (с использованием Ubuntu), соединение работает отлично, компиляции серверов и клиент предоставляют номер IP и порта.C - Создание бесконечного соединения сокетов между сервером и клиентом (Linux)

Но когда соединение установлено, клиент может только send one message, а затем connection closes. Когда клиент отправляет сообщение, сервер получает его и программу ends by itself.

Я попытался использовать while loop, но затем он дает мне Error on binding. Есть ли способ сделать это бесконечным, так что когда пользователь вводит exit или некоторые specific key/command, программа заканчивается.

server.c ОБНОВЛЕНО с WHILE LOOP

#include<stdio.h> 
#include<stdlib.h> 
#include<sys/types.h>  
#include<sys/socket.h> 
#include<netinet/in.h> 
#include<string.h> 

int main(int argc, char *argv[]) 
{ 
     int sockfd, newsockfd, portNum, clien, n; 
     char buffer[256]; 
     struct sockaddr_in serv_addr,cli_addr; 
    if (argc < 2) 
    { 
     fprintf(stderr, "\nno port provided"); 
     exit(1); 
    } 

    sockfd = socket(AF_INET,SOCK_STREAM, 0); 
    if (sockfd < 0) 
     printf("\nprovide a valid port number\n"); 

    bzero((char *)&serv_addr, sizeof(serv_addr)); 
    portNum = atoi(argv[1]); 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portNum); 

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
     printf("error on binding"); 

    while(1) 
    { 
     listen(sockfd,5); 
    } 
    clien = sizeof(cli_addr); 
    newsockfd=accept(sockfd, (struct sockaddr *) &cli_addr, &clien); 

    if (newsockfd < 0) 
     printf("=> Error on accepting...\n"); 

    bzero(buffer, 256); 
    n = read(newsockfd, buffer, 256); 

    if (n < 0) 
     printf("error reading from socket...\n"); 

    printf("%s\n", buffer); 
    n = write(newsockfd, "message received.", 58); 

    if (n < 0) 
     printf("cannot write from socket...\n"); 

    return 0; 
} 

client.c ОБНОВЛЕНО с WHILE LOOP

#include<stdio.h> 
#include<stdlib.h> 
#include<sys/types.h>  
#include<sys/socket.h> 
#include<netinet/in.h> 
#include<netdb.h> 
#include<string.h> 

int main(int argc, char *argv[]) 
{ 
     int sockfd,portno,n; 
     char buffer[256]; 
     struct sockaddr_in serv_addr; 
     struct hostent *server; 

     //while(counter != 5) 
     // /{ 
      if (argc < 3) 
     { 
      fprintf(stderr,"Usage %s hostname port...\n",argv[0]); 
      exit(1); 
     } 

     portno = atoi(argv[2]); 
     sockfd = socket(AF_INET, SOCK_STREAM, 0); 
     if (sockfd < 0) 
      printf("\error opening socket...\n"); 

     bzero((char *) &serv_addr, sizeof(serv_addr)); 
     server = gethostbyname(argv[1]); 

     if (server == NULL) 
     { 
      fprintf(stderr,"no such host...\n"); 
      exit(0); 
     } 

     serv_addr.sin_family = AF_INET; 
     bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length); 
     serv_addr.sin_port = htons(portno); 

     if (connect(sockfd, &serv_addr,sizeof(serv_addr)) <0) 
      printf("\error connecting\n"); 

     printf("your message:"); 
     fgets(buffer, 256, stdin); 
     while(1) 
     { 
      n = write(sockfd,buffer,strlen(buffer)); 
     } 
     if (n < 0) 
      printf("error writing to socket\n"); 

     n = read(sockfd, buffer, 255); 

     if (n < 0) 
      printf("error reading from socket\n"); 

     printf("%s\n", buffer);   

     return 0; 
} 

Спасибо.

+0

Вы должны быть обязательные один раз, но для прослушивания соединений в то время цикла. В настоящее время, как вы его кодировали, серверный процесс заканчивается, как только он получает (или не получает) сообщение. – mittmemo

+0

вы можете использовать функцию setsocketoptions(), чтобы включить «keepalive». Тогда соединение не будет закрыто, пока клиентский или серверный конец не выйдет из программы или сокет не будет явно закрыт (предпочтительно: «shutdown (socket, SHUT_RDWR); (socket); ' – user3629249

+0

keepalive можно установить с помощью:' INT32 keepAlive = 1; INT32 result = 0; result = setsockopt (socket, SOL_SOCKET, SO_KEEPALIVE и keepAlive, (socklen_t) sizeof (keepAlive)); ' – user3629249

ответ

1

Проблема с вашим сервером заключается в том, что вы немедленно прекращаете всякий раз, когда получаете сообщение. Вам следует продолжать слушать функцию recv() до тех пор, пока клиент не отключится. Вот один фрагмент кода, который должен сделать трюк.

Отказ от ответственности: Однако я не проверял его, это из старого проекта, который я модифицировал для вас на лету, он должен работать, но я не уверен на 100%, я не успеваю его проверить теперь, но не стесняйтесь задавать вопросы, если что-то не так, я попытаюсь исправить это.

EDIT: попытка повторного бина вызывает ошибку, поскольку привязка уже выполнена, и порт уже занят, поэтому вы не можете «назначить» другую программу на этот порт, поэтому вы получите сообщение об ошибке. Единственное, что вам нужно сделать, это убедиться, что ваш сервер слушает, пока клиент не отключится от сервера.

Также возможно, что некоторая часть кода была сделана для C++ в какой-то момент, но сетевая часть должна работать нормально.

Не стесняйтесь попробовать и прокомментировать, если у вас есть вопросы. Server.c:

int socket_desc , client_sock , c , *new_sock; 
    struct sockaddr_in server , client; 

    socket_desc = socket(AF_INET , SOCK_STREAM , 0); 
    if (socket_desc == -1) 
    { 
     //HANDLE ERROR 
    } 
    printf("Socket created\n"); 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(8000); 

    //Binding, you already do it correctly. 
    if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server))< 0) 
    { 
     //ERROR 
    } 
    printf("bind done"); 

    //Listen 
    listen(socket_desc , 3); 

    printf("Waiting for incoming connections..."); 
    c = sizeof(struct sockaddr_in); 


    while((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))) 
    { 
     puts("Connection accepted"); 

     pthread_t sniffer_thread; 
     new_sock = (int*) malloc(1); 
     *new_sock = client_sock; 

     if(pthread_create(&sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0) 
     { 
      //ERROR 
     } 

     printf("Handler assigned"); 
    } 

    if (client_sock < 0) 
    { 
     //ERROR 
    } 

    //return 0; 

} 

/* 
* This will handle connection for each client you may have and read indefinitely 
* */ 
void *connection_handler(void *socket_desc) 
{ 
    //Get the socket descriptor 
    int sock = *(int*)socket_desc; 
    int read_size; 
    char *message , client_message[2000]; 
    string smatrix ; 
    int ind ; 
    string tok ; 
    int i = 0 ; 


    //Receive a message from client 
    while((read_size = recv(sock , client_message , 2000 , 0)) > 0) 
    { 
     //What you want to do with the client's message 
    } 

    if(read_size == 0) 
    { 
     printf("Client disconnected"); 
     fflush(stdout); 
    } 
    else if(read_size == -1) 
    { 
     //ERROR 
    } 

    //Free the socket pointer 
    free(socket_desc); 

Что касается клиента, сделать время цикла до определенного времени прошло или заданный символ или значение вводится.Что-то вроде:

while(wantToExit == false){ 
    char a; 
    printf("Please enter a char"); 
    scanf("%c", &a); 
    write(sock , a , 1); //Note use strlen() for strings 
} 

Надеется, что это помогает

+0

Я добавил цикл while к моему серверному/клиентскому коду, теперь он бесконечен, но теперь, когда клиент отправляет сообщение, сервер не отображает его. Как их отобразить. Вы, в то время как цикл сделал мой код, но как я могу закончить программу, когда пользователь вводит «выход»? – hassanyf

+0

@moose: Стандартное предупреждение: не бросать 'void *'. Это устаревшие вещи и сильно устарели. Он будет подавлять предупреждения компилятора для недопустимых типов. Прочитайте [здесь] (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). Обратите внимание, что компилятор - ваш друг. – Olaf

+1

@moose хорошо, вам придется сканировать сообщение клиента, и всякий раз, когда вы отправляете сообщение, вы завершаете цикл сервера. Но это должен быть другой вопрос. Примите мой ответ, если он помог – LBes

1

Что вы на самом деле ожидаете от сервера? Вы открываете/читаете/завершаете. Прекращение, конечно, закрывает сокет неявно - к счастью, поскольку вы забыли закрыть явно.

Вы должны постоянно читать из гнезда. Не уверен, что вы подразумеваете под «это ... дает мне ошибку при привязке»; если вы пытаетесь перевязать, это, конечно, неправильно. Вы не открывали бы файл снова и снова, и ... просто чтобы прочитать его данные.

Если вы хотите прослушивать гнездо после того, как он был закрыт с другой стороны, просто введите listen во внешний цикл.

Прочитать Wikipedia для основ около sockets и проверить ссылки.

+0

Я добавил некоторое время loop to my listen(), но теперь клиент продолжает отправлять сообщения, но не выводит на экран сервера, server.c также работает, но ничего не выводит. Как заставить программу завершить работу, когда клиент входит в «exit Мне нужно добавить какое-то условие вроде while (msg! = 'Exit') – hassanyf

+0

IIRC, только чтение возвращается с 0 байтами, если ссылка была закрыта. Но что вы на самом деле хотите? Вы написали, что хотите, сервер работает, теперь вы wan t прекратить работу, когда клиент отключится. Выбери один. И читайте о программировании сокетов. Это все в документах. Пожалуйста, поймите, что это не учебный сайт. – Olaf

+0

Для завершения по команде: просто закончите цикл while, когда вы получите соответствующее сообщение. – Olaf

Смежные вопросы