2013-03-24 75 views
2

我有一個程序創建一個套接字(服務器和客戶端程序)並通過使用該套接字的TCP端口發送消息。我的問題是,我如何交換多條消息? 每當我發送一條消息,端口就會關閉,我需要使用另一個端口發送另一條消息。通過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[] = 
     "" 
     "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; 
} 

因此,例如,我運行的代碼,並得到本作服務器端:

[email protected] ~/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 

[email protected] ~/Desktop/Mreze/Lab1/rijeseno $ 

而且在客戶端:

[email protected] ~/Desktop/Mreze/Lab1/rijeseno $ ./client2 localhost 5000 
1. broj za slanje: 45 
2. broj za slanje: 56 
Suma iznosi: 101 

我試圖把一個while循環,所以它與循環發送,但沒有成功的一部分。請向我解釋我應該把它放在哪裏,以便它能正常工作。謝謝!

+0

直到你用它做不關閉套接字? – Hasturkun 2013-03-24 15:29:54

+0

是您的原始輸出。你需要它? – 2013-03-24 15:32:24

+0

我總是搞亂輸出。謝謝,無論誰編輯它。 @Hasturkun,我試過這樣做,我得到連接拒絕下一次客戶端連接嘗試連接 – Juraj 2013-03-24 15:35:16

回答

2

這裏有一個問題:

n = read (newsockfd, buffer, 255); 

你做什麼,你是執行讀取一次,該數據可能不完全可用。事實是,您需要讀取數據,只要您完全收到數據,或檢測到EOF狀況(返回值爲-1)。

通常,您需要爲接收部分編寫更可靠的代碼,因爲在流協議中不保證消息邊界以任何形式保存。

這裏是一個(非常unoptimal,但簡單)讀取數據代碼:

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

首先把你的connection()函數放在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); 
+0

我也這樣做了,並在客戶端連接被拒絕 – Juraj 2013-03-24 15:41:43

+0

@Juraj連接之前()你有一些地址準備一步,你必須在循環之前把它們全部轉移到外 – 2013-03-24 15:45:27

+0

謝謝,我一回家就會嘗試! – Juraj 2013-03-24 15:53:55