2016-09-25 5 views
0

У меня есть следующий код клиента и сервера.Отправить и получить сообщение на обоих концах

server.c

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

#define MAX_DATA 1024 
#define BUFFER 1024 

int _GetHostName(char *buffer, int lenght); 

const char MESSAGE[]="Hello, World!\n"; 
const int BACK_LOG=5; 

int main(int argc, char *argv[]){ 
    int serverSocket=0, on=0, port=0, status=0, childPid=0; 
    struct hostent *hostPtr=NULL; 
    char hostname[80]=""; 
    char data[MAX_DATA]; 
    struct sockaddr_in serverName={0}; 

    char input[BUFFER]; 
    char output[BUFFER]; 
    int len; 


    if(2!= argc){ 
     fprintf(stderr, "Usage : %s <port>\n", argv[0]); 
     exit(1); 
    } 
    port=atoi(argv[1]); 
    serverSocket=socket(PF_INET,SOCK_STREAM, IPPROTO_TCP); 
    if(-1==serverSocket){ 
     perror("socket()"); 
     exit(1); 
    } 

    on=1; 
    status=setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); 
    if(-1==status){ 
     perror("setsockopt(...,SO_REUSEADDRE,...)"); 
    } 

    { 
     struct linger linger={0}; 
     linger.l_onoff=1; 
     linger.l_linger=30; 
     status=setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger)); 
     if(-1==status){ 
      perror("setsockopt(...,SO_LINGER,...)"); 
     } 
    } 

    status=_GetHostName(hostname, sizeof(hostname)); 
    if(-1==status){ 
     perror("_GetHostName()"); 
     exit(1); 
    } 

    hostPtr=gethostbyname(hostname); 
    if(NULL==hostPtr){ 
     perror("gethostbyname()"); 
     exit(1); 
    } 

    (void)memset(&serverName,0,sizeof(serverName)); 
    (void)memcpy(&serverName.sin_addr, hostPtr->h_addr,hostPtr->h_length); 

    serverName.sin_family=AF_INET; 
    serverName.sin_port=htons(port); 

    status=bind(serverSocket, (struct sockaddr*)&serverName,sizeof(serverName)); 
    if(-1==status){ 
     perror("bind"); 
     exit(1); 
    } 


    status=listen(serverSocket, BACK_LOG); 
    if(-1==status){ 
     perror("listen()"); 
     exit(1); 
    } 

    for(;;){ 
     struct sockaddr_in clientName={0}; 
     int slaveSocket, clientLength=sizeof(clientName); 

     (void)memset(&clientName,0,sizeof(clientName)); 

     slaveSocket=accept(serverSocket,(struct sockaddr*)&clientName, & clientLength); 
     if(-1==slaveSocket){ 
      perror("accept()"); 
      exit(1); 
     } 

     childPid=fork(); 

     switch(childPid){ 
      case -1:perror("fork()"); 
      exit(1); 
      case 0: close(serverSocket); 
      if(-1==getpeername(slaveSocket, (struct sockaddr*)&clientName, &clientLength)){ 
       perror("getpeername()"); 
      }else{ 
       printf("Connection request from %s \n", inet_ntoa(clientName.sin_addr)); 

       int data_len=1; 

       while(data_len){ 
        data_len=recv(slaveSocket,data, MAX_DATA,0); 
        if(data_len){ 
         //send(slaveSocket,data,data_len,0); 

         data[data_len]='\0'; 
         printf("CLIENT: %s", data); 

         printf("SERVER : "); 
         fgets(input,BUFFER, stdin); 
         send(slaveSocket, input, strlen(input),0); 
        } 


       } 

      } 

      printf("Client disconnected\n"); 
      close(slaveSocket); 
      exit(0); 
      default:close(slaveSocket); 
     } 
    } 
    return 0; 
} 

int _GetHostName(char *buffer,int length){ 
    struct utsname sysname={0}; 
    int status=0; 

    status=uname(&sysname); 
    if(-1!=status){ 
     strncpy(buffer,sysname.nodename,length); 
    } 
    return(status); 
} 

client.c

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <string.h> 


#define BUFFER 1024 

int main(int argc, char *argv[]){ 
    int clientSocket, remotePort, status=0; 
    struct hostent *hostPtr=NULL; 
    struct sockaddr_in serverName={0}; 
    char buffer[256]=""; 
    char *remoteHost=NULL; 

    char input[BUFFER]; 
    char output[BUFFER]; 
    int len; 


    if(3!=argc){ 
     fprintf(stderr, "Usage: %s <serverHost> <serverPort> \n",argv[0]); 
     exit(1); 
    } 
    remoteHost=argv[1]; 
    remotePort=atoi(argv[2]); 
    clientSocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); 
    if(-1==clientSocket){ 
     perror("socket()"); 
     exit(1); 
    } 

    hostPtr=gethostbyname(remoteHost); 
    if(NULL==hostPtr){ 
     hostPtr=gethostbyaddr(remoteHost,strlen(remoteHost), AF_INET); 
     if(NULL==hostPtr){ 
      perror("Error resolving server address "); 
      exit(1); 
     } 
    } 
    serverName.sin_family=AF_INET; 
    serverName.sin_port=htons(remotePort); 
    (void)memcpy(&serverName.sin_addr,hostPtr->h_addr,hostPtr->h_length); 

    status=connect(clientSocket,(struct sockaddr*)&serverName,sizeof(serverName)); 
    if(-1==status){ 
     perror("connect()"); 
     exit(1); 
    } 

    while(1){ 
     printf("CLIENT: "); 
     fgets(input,BUFFER, stdin); 
     send(clientSocket, input, strlen(input),0); 

     len=recv(clientSocket, output,BUFFER, 0); 
     output[len]='\0'; 
     printf("SERVER : %s\n",output); 
    } 
    close(clientSocket); 


} 

Серверный код выше может получать и отправлять сообщения от и к клиенту. Клиент также может получать и отправлять сообщения с сервера и на сервер. Однако они могут отправлять только одно сообщение за раз. Прежде чем клиент сможет отправить больше сообщений, ему нужно дождаться, когда сервер отправит одно сообщение. То же самое с сервером. Как заставить их получать и отправлять несколько сообщений, не дожидаясь ответа другого конца?

enter image description here

+0

Я не понимаю, что вы подразумеваете под «несколькими сообщениями». Вы можете легко заставить сервер обрабатывать несколько клиентов, что, я думаю, ваш код уже делает. Попробуйте запустить несколько экземпляров клиента и посмотреть, хотите ли вы этого. –

+0

Я имею в виду, что если клиент отправит сообщение в первый раз, он будет отправлен успешно. Но если он снова отправляется, он не может отправить, потому что он должен сначала ждать ответа сервера. Если сервер отправляет сообщение, то именно в это время клиент может успешно отправить его снова.Основной вопрос заключается в том, как создать цикл while, который ожидает входящего сообщения и в то же время принимает ввод, который будет отправлен другому. – beginner

+0

на скриншоте, включенном на стороне клиента, говорится: «КЛИЕНТ:» означает его время для отправки, пока сервер ждет сообщения от клиента и не может отправить его еще. после отправки клиента сервер отобразит сообщение, отправленное клиентом, и это время, когда он может отправить сообщение, и клиент будет ждать входящего сообщения. – beginner

ответ

1

Я понимаю, что вы хотите продолжить передачу, не дожидаясь ответа сервера.

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

int pollForData(int sock) { 
    struct pollfd pollSock; 
    pollSock.fd = sock; 
    pollSock.events = POLLIN; 
    return poll(&pollSock, 1, 10); 
} 
+0

Почему он говорит, 'размер хранилища 'pollSock' неизвестен'? – beginner

+0

Вам необходимо включить соответствующие заголовки. 'poll.h' содержит определения для' pollfd'. –

+0

Я попробовал это как 'int data_len; while (1) { if (pollForData (slaveSocket)) { data_len = recv (slaveSocket, data, MAX_DATA, 0); данные [data_len] = '\ 0'; printf ("КЛИЕНТ:% s", данные); } else { printf ("СЕРВЕР:"); fgets (вход, BUFFER, stdin); отправить (slaveSocket, input, strlen (input), 0); } } 'он позволяет отправлять много массажей, но не будет отображаться сразу. – beginner

1

Использование select() на сокете и на stdin и выполнить чтение/получить из любого из обоих становится готов к чтению. Если чтение выполняется, напишите/отправьте либо stdout, либо в гнездо.

В сервере «гнездо» будет относиться к принял гнездо, в клиенте к гнезду на подключен.


Unrelated, но все-таки важно:

Это

char data[MAX_DATA]; 

... 

data_len=recv(slaveSocket,data, MAX_DATA,0); 
if(data_len){ 
    data[data_len]='\0'; 

... 

может привести переполнение буфера в тот момент не поступило MAX_DATA байт, а затем 0 будет записано 1 с конца data.

Чтобы исправить это определить data так:

char data[MAX_DATA + 1]; 

Также все код полностью промахов проверки ошибок для звонков в recv() и send(). Это плохо.

+0

Благодарим вас за сообщение об ошибке. Извините, но я действительно не знаю, как использовать 'select'. Можете ли вы дать мне простой пример? – beginner

+0

@quickbrownfox: https://www.google.com/search?q=example+on+how+to+use+select+to+monitor+stdin+and+socket вызывает http://stackoverflow.com/q/5825748/694576 и тонны других. Посмотрите, как далеко вы доберетесь, а затем вернитесь сюда с другим конкретным вопросом, пожалуйста. – alk

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