2

ソケットを作成するプログラム(サーバーおよびクライアントプログラム)があり、そのソケットを使用してTCPポート経由でメッセージを送信します。私の質問は、どうすれば複数のメッセージを交換できますか?メッセージを送信するたびにポートが閉じられ、別のポートを使用して別のメッセージを送信する必要があります。

たとえば、クライアントからサーバーに2つの番号を送信する必要があり、サーバーは送信した番号の合計を返信する必要があります。同じポートを介して未定義の番号または2つの番号を送信するにはどうすればよいですか?

コードは次のとおりです(ほとんど標準的なもの):

サーバ:

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

char* Itoa(int value, char* str, int radix) 
{
    static char dig[] =
      "0123456789"
      "abcdefghijklmnopqrstuvwxyz";
    int n = 0, neg = 0;
    unsigned int v;
    char* p, *q;
    char c;
    if (radix == 10 && value < 0) {
      value = -value;
      neg = 1;
    }
    v = value;
    do {
      str[n++] = dig[v%radix];
      v /= radix;
    } while (v);
    if (neg)
      str[n++] = '-';
    str[n] = '\0';
    for (p = str, q = p + (n-1); p < q; ++p, --q)
      c = *p, *p = *q, *q = c;
    return str;
}

void error (const char *msg)
{
    perror (msg);
    exit (1);
}
int main (int argc, char *argv[])
{
    if (argc < 2)
    {
        fprintf (stderr, "ERROR, no port provided\n");
        exit (1);
    }
    //nova varijabla za sumiranje primljenih brojeva
    int suma=0;

    int sockfd, newsockfd, portno,i;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    for (i=0;i<2;i++)
    {
        sockfd = socket (AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) error ("ERROR opening socket");
        memset ((char *) &serv_addr, 0, sizeof (serv_addr));
        portno = atoi (argv[1]);
        portno+=i;
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = INADDR_ANY;
        serv_addr.sin_port = htons (portno);
        if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) error ("ERROR on binding");
        //test za ispis otvorenog porta
        printf("Uspjesno otvoren localhost na portu %d\n", portno); 
        listen (sockfd, 5);
        clilen = sizeof (cli_addr);
        newsockfd = accept (sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0) error ("ERROR on accept");
        memset (buffer, 0, 256);
        n = read (newsockfd, buffer, 255);
        if (n < 0) error ("ERROR reading from socket");
        printf ("%d. proslan broj: %s\n", i+1, buffer);
//print
        suma=suma+atoi(buffer);
//radi!!        printf("suma je %d\n", suma);
//od klijenta: n = write (sockfd, buffer, strlen (buffer));
//char *  itoa ( int value, char * str, int base );
        Itoa(suma, buffer, 10);
        n = write (newsockfd, buffer, strlen(buffer));
        if (n < 0) error ("ERROR writing to socket");
        close (newsockfd);
        close (sockfd);
    }
    return 0;
}

クライアント:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void    error (const char *msg)
{
    perror (msg);
    exit (1);
}
int
main (int argc, char *argv[])
{
    if (argc < 3)
    {
        fprintf (stderr, "usage %s hostname port\n", argv[0]);
        exit (1);
    }
    int sockfd, portno, n,i;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[256];
    for (i=0;i<2;i++)
    {
        portno = atoi (argv[2]);
        sockfd = socket (AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
        error ("Ne mogu otvoriti socket!");
        server = gethostbyname (argv[1]);
        if (server == NULL)
        {
            fprintf (stderr, "Greska, ne postoji!\n");
            exit (1);
        }
        memset ((char *) &serv_addr, 0, sizeof (serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy ((char *) server->h_addr,
        (char *) &serv_addr.sin_addr.s_addr,
        server->h_length);
        portno+=i;
        serv_addr.sin_port = htons (portno);
        if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
        error ("ERROR connecting");
        printf ("%d. broj za slanje: ", i+1);
        memset (buffer, 0, 256);
        fgets (buffer, 255, stdin);
        n = write (sockfd, buffer, strlen (buffer));
        if (n < 0)
        error ("ERROR writing to socket");
        memset (buffer, 0, 256);
        n = read (sockfd, buffer, 255);
        if (n < 0)
        error ("ERROR reading from socket");
        if (i==1) printf ("Suma iznosi: %s\n", buffer);
        close (sockfd);
    }
    return 0;
}

したがって、たとえば、コードを実行してサーバー側でこれを取得します。

j@PC ~/Desktop/Mreze/Lab1/rijeseno $ ./server2 5000
Uspjesno otvoren localhost na portu 5000
1. proslan broj: 45

Uspjesno otvoren localhost na portu 5001
2. proslan broj: 56

j@PC ~/Desktop/Mreze/Lab1/rijeseno $ 

そしてクライアント側では:

j@PC ~/Desktop/Mreze/Lab1/rijeseno $ ./client2 localhost 5000
1. broj za slanje: 45
2. broj za slanje: 56
Suma iznosi: 101

whileループを入れてみたので、送信してパーツをループしましたが、成功しませんでした。それが機能するように、どこに置くべきか説明してください。ありがとうございました!

4

2 に答える 2

2

ここに問題があります:

n = read (newsockfd, buffer, 255);

読み取りを1回実行すると、データが完全に利用できない場合があります。-1実際には、データを完全に受信するか、EOF状態(戻り値)を検出する限り、データを読み取る必要があります。

ストリームプロトコルではメッセージの境界がどのような形式でも維持されることが保証されていないため、通常、受信部分に対してより信頼性の高いコードを記述する必要があります。

データを読み取るための(非常に最適ではないが単純な)コードは次のとおりです。

int readLine(int fd, char data[])
{
   size_t len = 0;
   while (len < maxlen)
   {
      char c;
      int ret = read(fd, &c, 1);
      if (ret < 0)
      {
          data[len] = 0;
          return len; // EOF reached
      }
      if (c == '\n')
      {
          data[len] = 0;
          return len; // EOF reached
      }
      data[len++] = c;
   }
}

そして使用例:

char buffer[256];
int num1, num2;

readLine(newsockfd, buffer);
num1 = atoi(buffer);
readLine(newsockfd, buffer);
num2 = atoi(buffer);
于 2013-03-24T16:04:47.473 に答える
1

まず、connection()関数をforループの前に置き、close()を後に置きます。アイデアのためだけに

connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)
for (i=0;i<n;i++){
 // do you introspection with server
 // actually send number to server 
}
// Code to read result: SUM from server
close (sockfd);
于 2013-03-24T15:37:50.307 に答える