2016-09-25 214 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