2016-09-25 263 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; (1){if(pollForData(slaveSocket)){data_len = recv(slaveSocket,data,MAX_DATA,0); data [data_len] ='\ 0'; printf(「CLIENT:%s」,data); } else { printf(「SERVER:」); fgets(input,BUFFER,stdin); 發送(slaveSocket,輸入,strlen(輸入),0); } }'它可以發送很多按摩,但不會立即顯示。 – beginner

1
使用 select()的插座和 stdin和執行讀

/接收來自任何一個的都準備好讀。如果讀取完成,則寫入/發送到stdout或發送到插座。

在服務器「插座」就指的是接受插座,在客戶端的連接插座


無關,但仍然很重要:

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