C сокет программирования, как получить несколько сообщений? - PullRequest
0 голосов
/ 18 ноября 2018

У меня есть приложение сервер / клиент, и я пытаюсь заставить сервер читать каждое сообщение, которое клиент отправляет ему, и отправлять его обратно клиенту для печати.пока у меня есть сервер, читающий первое сообщение и отправляющий его клиенту, и он печатает нормально, но когда второе сообщение отправляется от клиента, я пытаюсь распечатать его из функции HandleTcpClient, чтобы проверить его, и он просто печатает ноль,я не уверен, правильно ли он его получает

код клиента:

#include <stdio.h> //include standard input/output library
#include <stdlib.h> //include standard libraries
#include <string.h> //include string headers 
#include <unistd.h> //add definitions for constansts and functions 
#include <sys/types.h> // include definitions for different data types
#include <sys/socket.h> //include socket support
#include <netinet/in.h> //define internet protocol functions
#include <arpa/inet.h> //define internet protocol functions
#include "Practical.h" //include practical header file

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

char myIP[16];
unsigned int myPort;
struct sockaddr_in server_addr,myaddr;
char username[] = "CharlieA";
  if (argc < 2 || argc > 3) // Test for correct number of arguments
    DieWithUserMessage("Parameter(s)",
        "<Server Address> [<Server Port>]");

  char *servIP = argv[1];     // First arg: server IP address (dotted quad)


  // Third arg (optional): server port (numeric).  7 is well-known echo port
  in_port_t servPort = atoi(argv[2]);  //21
printf("serv port: %d\n",servPort);


 // Create a reliable, stream socket using TCP  //23
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//this block of code creates a reliable tcp stream socket and checks what the returned integer is from the socket function, the returned function will give a integer that descibes the socket. if this is 0 then kill the socket and show the user an error message.
  if (sock < 0)
    DieWithSystemMessage("socket() failed"); //26

  // Construct the server address structure //28
  struct sockaddr_in servAddr;            // Server address
  memset(&servAddr, 0, sizeof(servAddr)); // Zero out structure
  servAddr.sin_family = AF_INET;          // IPv4 address family
  // Convert address
  int rtnVal = inet_pton(AF_INET, servIP, &servAddr.sin_addr.s_addr);
  if (rtnVal == 0)
    DieWithUserMessage("inet_pton() failed", "invalid address string");
  else if (rtnVal < 0)
    DieWithSystemMessage("inet_pton() failed");
  servAddr.sin_port = htons(servPort);    // Server port
  myaddr.sin_addr.s_addr = INADDR_ANY;

  // Establish the connection to the echo server
  if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
    DieWithSystemMessage("connect() failed"); 

 //get address of bound socket after connect function call (binds automatically with connect method)
bzero(&myaddr,sizeof(myaddr));
int len = sizeof(myaddr);
getsockname(sock,(struct sockaddr *) &myaddr, &len);
inet_ntop(AF_INET, &myaddr.sin_addr, myIP, sizeof(myIP)); //convert network address to string
myPort = ntohs(myaddr.sin_port); //convert from netshort to hostbyte order

//getlocal ip address to be sent to server
char *echoString=(char*)malloc(13*sizeof(char));
sprintf(echoString,"netsrv type0 %s %s-%u\r\n",username,myIP,myPort); //generate request string
size_t echoStringLen = strlen(echoString); // Determine input length //44
size_t iplen = strlen(myIP);


  // Send the string to the server
  ssize_t numBytes = send(sock,echoString, echoStringLen, 0);
  printf("sent: %s", echoString);

  if (numBytes < 0) //sending string to server, number of bytes of the message is equal to return value of send function, if the number of bytes is less than 0 then do not send and say to user that the send failed
    DieWithSystemMessage("send() failed");
  else if (numBytes != echoStringLen)
    DieWithUserMessage("send()", "sent unexpected number of bytes"); //51

// if the number of bytes is not equal to the input length of the string parsed as an argument then die with the message to the user saying sent unexpected number of bytes.
    //send IP to server
send(sock,myIP,iplen,0); //send client IP
  // Receive the same string back from the server  //53
  unsigned int totalBytesRcvd = 0; // Count of total bytes received

  while (totalBytesRcvd < echoStringLen) {
    char buffer[BUFSIZE]; // I/O buffer
    /* Receive up to the buffer size (minus 1 to leave space for
     a null terminator) bytes from the sender */
    numBytes = recv(sock, buffer, BUFSIZE - 1, 0);
    if (numBytes < 0)
      DieWithSystemMessage("recv() failed");
    else if (numBytes == 0)
      DieWithUserMessage("recv()", "connection closed prematurely");
    totalBytesRcvd += numBytes; // Keep tally of total bytes
    buffer[numBytes] = '\0';    // Terminate the string!
    fputs("Received: ", stdout);     // Setup to print the echoed string
    fputs(buffer, stdout);      // Print the echo buffer


  }

  fputc('\n', stdout); // Print a final linefeed //70

  close(sock);
  exit(0);
}
//closing off connections to clean up data left over.

Второе сообщение - строка комментария отправляющего IP-клиента

Сервер:

#include <stdio.h> //include standard input/output library
#include <stdlib.h> //include standard libraries
#include <string.h> //include string headers 
#include <sys/types.h> //add definitions for constansts and functions 
#include <sys/socket.h> // include definitions for different data types
#include <netinet/in.h>  //define internet protocol functions
#include <arpa/inet.h> //define internet protocol functions
#include "Practical.h" //include pactical

static const int MAXPENDING = 5; // Maximum outstanding connection requests
static const int servPort = 48031;
int main(int argc) {//run on command line = "echoSvr <port>";argc = 2 command and parameter-  argv[0] = echoSvr and argv[1] = <port>

  // Create socket for incoming connections
  int servSock; // Socket descriptor for server
  if ((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    DieWithSystemMessage("socket() failed");
// this block of code is creating a socket stream to accept the incoming connections from clients 

  // Construct local address structure
  struct sockaddr_in servAddr;                  // Local address; internet socket address structure
  memset(&servAddr, 0, sizeof(servAddr));       // Zero out structure
  servAddr.sin_family = AF_INET;                // IPv4 address family
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface; host to network long[integer]
  servAddr.sin_port = htons(servPort);          // Local port; host to network short[integer]

  // Bind to the local address
  if (bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0)//cast servaddr as generic socket address structure
    DieWithSystemMessage("bind() failed");

  // Mark the socket so it will listen for incoming connections
  if (listen(servSock, MAXPENDING) < 0)
    DieWithSystemMessage("listen() failed");

setvbuf (stdout, NULL, _IONBF, 0);
printf("Listening on port: %d \n" , servPort);
printf("awaiting connection from client.... \n");
// this block of code binds the socket to the address of the server and tells the binded to socket to begin listening in for connections coming from client machines 
  for (;;) { // Run forever
    struct sockaddr_in clntAddr; // Client address
    // Set length of client address structure (in-out parameter)
    socklen_t clntAddrLen = sizeof(clntAddr);

    // Wait for a client to connect
    int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);
    if (clntSock < 0)
      DieWithSystemMessage("accept() failed");
//this block of code waits for a client to connect to the socket and then accepts the connection from the client and prints the clients details out to screen
    // clntSock is connected to a client!

    char clntName[INET_ADDRSTRLEN]; // String to contain client address
    if (inet_ntop(AF_INET, &clntAddr.sin_addr.s_addr, clntName,
        sizeof(clntName)) != NULL)
      printf("Handling client %s/%d\n", clntName, ntohs(clntAddr.sin_port));
    else
      puts("Unable to get client address");

    HandleTCPClient(clntSock);
  }
}

Функция HandleTCPClient:

void HandleTCPClient(int clntSocket) {
  char buffer[BUFSIZE]; // Buffer for echo string
  char *clientIP;

  unsigned int clientPort;
  // Receive message from client
  ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
  if (numBytesRcvd < 0)
    DieWithSystemMessage("recv() failed");

//get ip and port of clntSocket to apply to greeting string

  // Send greeting string and receive again until end of stream
  while (numBytesRcvd > 0) { // 0 indicates end of stream
    // Echo message back to client
    ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0);
    if (numBytesSent < 0)
      DieWithSystemMessage("send() failed");
    else if (numBytesSent != numBytesRcvd)
      DieWithUserMessage("send()", "sent unexpected number of bytes");

    // See if there is more data to receive
    numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
    if (numBytesRcvd < 0)
      DieWithSystemMessage("recv() failed");

    //recv client ip and assign to variable to hold
    recv(clntSocket,clientIP,100,0);
    printf("clientIP : %s" ,clientIP);
  }

close(clntSocket); // Close client socket
}

Я пытаюсь напечатать clientIP с помощью функции printf, и это где я получаю ноль, он просто, кажется, не получает его, естьздесь много кода, я выкладываю все это на всякий случай

1 Ответ

0 голосов
/ 18 ноября 2018

Это много кода, поэтому я не смотрел на него. Я заметил, однако:

char *echoString=(char*)malloc(13*sizeof(char));
sprintf(echoString,"netsrv type0 %s %s-%u\r\n",username,myIP,myPort);

Нигде вы не объясняете, откуда это 13, но явно недостаточно хранить отформатированную строку, которую выдаст sprintf. Достаточно провести 12-символьную строку (плюс терминатор NUL), которая даст вам netsrv type0. Это нужно исправить, так как sprintf закроет случайную память, которая ей не принадлежит, но это, вероятно, не ваша непосредственная проблема. (Используйте snprintf. Еще проще, если вы используете Linux / OSX / FreeBSD, это asprintf.)

Я думаю, что ваша проблема может быть в следующем:

numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
//recv client ip and assign to variable to hold
recv(clntSocket,clientIP,100,0);
printf("clientIP : %s" ,clientIP);

Вы никогда не смотрите на данные, полученные при первом вызове recv(). Возможно, вы заблуждаетесь, что каждый send каким-то образом отмечает отправляемые данные, так что recv будет считывать только данные, отправленные одним send. Это не тот случай. TCP - это потоковый протокол; данные представляют собой просто невыделенную серию байтов, и каждый recv() получает все, что доступно, с учетом ограничения размера при вызове. Так что вполне возможно, что результат обоих вызовов send() будет отображен в первом вызове recv().

Я думаю, что это, вероятно, объяснено в любом тексте / учебнике / руководстве, которое вы используете для написания этого кода, но если нет, я настоятельно рекомендую найти копию W. Unix-программирование Р. Стивенса .

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

...