2010-03-03 158 views
0

我已經寫了一個客戶端和服務器c程序,我已經從示例代碼中獲得了。c程序客戶端服務器

我想寫一個迭代的客戶端和服務器程序, 即客戶端後,發送一個字符串,然後服務器打印該字符串,然後返回一個字符串,客戶端

然後在客戶端打印由服務器輸入的字符串等等,直到客戶端輸入'退出'退出。

我修改了客戶端和服務器是迭代

此外,如果客戶端輸入「退出」,程序將退出

但是我有一個問題的代碼,我不知道該怎麼使客戶端接收由服務器inputed字符串,我只能讓服務器接收客戶端的字符串

請隨時提供線索

非常感謝!

我的代碼

client.c

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <string.h> 
#include <stdarg.h> 
#include <winsock2.h> 

#define SA struct sockaddr 
#define S_PORT 4321 
#define BufferStoreLEN 1024 

void errexit(const char *format, ...) 
{ 
     va_list args; 
     va_start(args, format); 
     vfprintf(stderr, format, args); 
     va_end(args); 
     WSACleanup(); 
     exit(1); 
} 

int main(int argc, char **argv) 
{ 
     WSADATA wsadata; 
     SOCKET sockfd, listenfd, connfd; 
     int i, n, q, len, alen, out; 
     char str[BufferStoreLEN+1]; 
     char cmp[] = "exit"; 
     char* BufferStore; 
     struct sockaddr_in servaddr, cliaddr; 

     if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0) 
       errexit("WSAStartup failed\n"); 

     if (argc != 2) 
       errexit("wrong arg"); 

     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 
       errexit("socket error: error number %d\n", WSAGetLastError()); 

     memset(&servaddr, 0, sizeof(servaddr)); 
     servaddr.sin_family = AF_INET; 
     servaddr.sin_port = htons(S_PORT); 
     if ((servaddr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE) 
       errexit("inet_addr error: error number %d\n", WSAGetLastError()); 

     if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR) 
       errexit("connect error: error number %d\n", WSAGetLastError()); 

     do { 
       printf("Input: "); 
       scanf("%s", str); 
       out = htonl(strlen(str)); 
       BufferStore = malloc(strlen(str)); 
       for(i=0; i<strlen(str); i++) 
         BufferStore[i] = str[i]; 
       out = send(sockfd, BufferStore, strlen(str), 0); 
/*    
       if (strcmp(cmp, str) != 0) 
       { 
         printf("Server's response:\n"); 
         n = recv(connfd, BufferStore, BufferStoreLEN, 0); 

         while (n > 0) { 
           BufferStore[n] = '\0'; 
           printf("%s\n", BufferStore); 
           n = recv(connfd, BufferStore, BufferStoreLEN, 0); 
         } 
       }*/ 
     }while(strcmp(cmp,str)!=0); 

     closesocket(sockfd); 
     WSACleanup(); 
     free(str); 
     free(BufferStore); 
     return 0; 
} 

server.c

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <string.h> 
#include <stdarg.h> 
#include <winsock2.h> 
#include <Windows.h> 
#define SA struct sockaddr 
#define MAXLINE 4096 
#define S_PORT 4321 
#define BufferStoreLEN 1024 

void errexit(const char *format, ...) 
{ 
     va_list args; 
     va_start(args, format); 
     vfprintf(stderr, format, args); 
     va_end(args); 
     WSACleanup(); 
     exit(1); 
} 

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

     WSADATA wsadata; 
     SOCKET listenfd, connfd; 
     SOCKET sockfd; 
     int number, out; 
     int i, n, q, alen; 
     struct sockaddr_in servaddr, cliaddr; 
     char BufferStore[BufferStoreLEN+1]; 
     char* Store; 
     char str[BufferStoreLEN+1]; 
     int flag = 1; 

     if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0) 
       errexit("WSAStartup failed\n"); 

     listenfd = socket(AF_INET, SOCK_STREAM, 0); 
     if (listenfd == INVALID_SOCKET) 
       errexit("cannot create socket: error number %d\n", WSAGetLastError()); 

     memset(&servaddr, 0, sizeof(servaddr)); 
     servaddr.sin_family  = AF_INET; 
     servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
     servaddr.sin_port  = htons(S_PORT); 

     if (bind(listenfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR) 
       errexit("can't bind to port %d: error number %d\n", S_PORT, WSAGetLastError()); 

     if (listen(listenfd, 5) == SOCKET_ERROR) 
       errexit("can't listen on port %d: error number %d\n", S_PORT, WSAGetLastError()); 

     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 
       errexit("socket error: error number %d\n", WSAGetLastError()); 

     for (; ;) 
     { 
       alen = sizeof(SA); 
       connfd = accept(listenfd, (SA *) &cliaddr, &alen); 
       if (connfd == INVALID_SOCKET) 
         errexit("accept failed: error number %d\n", WSAGetLastError()); 

       n = recv(connfd, BufferStore, BufferStoreLEN, 0); 

       while (n > 0){ 
         BufferStore[n] = '\0'; 
         printf("%s\n", BufferStore); 
         printf("Input: "); 
         scanf("%s",str); 
         out = htonl(strlen(str)); 
         Store = malloc(strlen(str)); 
         for(q=0; q<strlen(str); q++) 
           Store[q] = str[q]; 
         out = send(sockfd, Store, strlen(str), 0); 
         n = recv(connfd, BufferStore, BufferStoreLEN, 0); 
       } 
       closesocket(sockfd); 
       WSACleanup(); 
       free(str); 
       free(BufferStore); 
     } 
} 

回答

0

你的服務器是一個無限循環中運行,所以能夠發送的數據被輸入服務器應用程序的客戶端應用程序,你必須閱讀在不同的線程的用戶輸入,然後發送給用戶,作爲無限循環當前正在阻止當前線程。

+0

您不需要多個線程在服務器中執行簡單的「讀取下一個命令,發送響應」循環(以及客戶端的反向)。 – 2010-03-03 15:01:36

0

有關流套接字(SOCK_STREAM)的一個重要理解是,它們爲您提供了一個字節(因此名稱:-)),沒有任何「數據包邊界」。

具體而言,如果從客戶端發送()100個字節的數據,則服務器可以RECV()它作爲

  • 一個的recv()調用返回100個字節
  • 2的recv()秒的50個字節,然後10的recv()1個字節
  • 第...等各
  • 一個的recv()90個字節...

您的代碼似乎假設你本身是什麼一端的nd()將在另一端的單個recv()調用中傳遞。對於小塊數據,這可能有用,但這不是你可以/應該依賴的。

一般來說,做一個命令/響應的場景像你設置,您需要有服務器識別「這是命令,我現在應該響應的結束」的方式。例如,如果您要發送文本字符串,則可以使用換行符(\ n)作爲「命令結束」標記。

服務器因而會做多種的recv()調用(每一個附加到一個緩衝器),直到它看到一個\ N(或錯誤),然後發送迴響應;客戶在閱讀回覆時會做類似的事情。