通过TCP端口发送多条消息

时间:2013-03-24 15:27:01

标签: c sockets unix tcp

我有一个创建套接字(服务器和客户端程序)的程序,并使用该套接字通过TCP端口发送消息。我的问题是,如何交换多条消息? 每当我发送消息时,端口都会关闭,我需要使用另一个端口发送另一条消息。

例如,我必须从客户端向服务器发送2个号码,服务器需要回复我发送的号码总和。如何通过SAME端口发送未定义的数字甚至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循环,所以它通过发送循环部分但没有成功。请向我解释我应该把它放在哪里才能正常工作。谢谢!

2 个答案:

答案 0 :(得分:2)

这是一个问题:

n = read (newsockfd, buffer, 255);

您执行的操作是执行一次读取,数据可能无法完全显示。事实是,只要您完全接收到数据或检测到EOF条件(-1返回值),您就需要读取数据。

通常,您需要为接收部分编写更可靠的代码,因为在流协议上无法保证您的消息边界以任何形式保留。

以下是用于读取数据的(非常不理想但简单的)代码:

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);

答案 1 :(得分:1)

首先将你的connection()函数放在for循环之后,然后在for循环之后关闭()。只是为了一个想法

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);