簡體   English   中英

C 使用用戶輸入的套接字編程服務器到客戶端

[英]C Socket Programming Server to Client using User Input

我正在嘗試修改一些客戶端和服務器 c 代碼,以便它在客戶端接收用戶輸入,將其發送到服務器,然后服務器發回相應的值。 我對c編程不是很熟悉; 因此,我的錯誤很可能與語法相關。 服務器代碼:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int main(int argc, char *argv[])
{
    int listenfd, connfd;
    struct sockaddr_in serv_addr; 

    char sendBuff[1025];
    char from_client[1025];
    time_t ticks; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    while(1)
    {
        connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

    recv(connfd, from_client, sizeof(from_client), 0);
    printf("%s", "Letter Recieved\n");
    if(from_client == 't')
    {
        ticks = time(NULL);
            snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, strlen(sendBuff));
    }
    if(from_client == 'n')
    {
        sendBuff == "Marcus Baker";
        send(connfd, sendBuff, sizeof(sendBuff), 0);
    }
    if(from_client == 'i')
    {
        sendBuff == "201604543";
        send(connfd, sendBuff, sizeof(sendBuff), 0);
    }
    if(from_client == 'q')
    {
        return 0;
    }

        close(connfd);
        sleep(1);
     }
}

客戶代碼:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

int main(int argc, char *argv[])
{
    int sockfd, n = 0;
    char letter[1024];
    printf("Enter a Character (t, n, i, q): ");
    scanf("%c",&letter);
    char recvBuff[1024];
    struct sockaddr_in serv_addr; 

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000); 

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
       printf("\n Error : Connect Failed \n");
       return 1;
    } 

    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
    {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF)
        {
            printf("\n Error : Fputs error\n");
        }
    } 

    if(n < 0)
    {
        printf("\n Read error \n");
    } 

    int toServer = send(sockfd, letter, sizeof(letter), 0);
    printf("%s", "Letter Sent\n");
    recv(sockfd, recvBuff, sizeof(recvBuff), 0);
    printf("%c", recvBuff);
    
    return 0;
}

任何信息將不勝感激。

我按照不同的堆棧溢出指南嘗試了幾次不同的迭代,但似乎都沒有用。 當我嘗試編譯這兩段代碼時,我收到有關代碼的用戶輸入部分的警告,關於 scanf 的某些內容需要一個 char*。

我建議你使用一個已知的好客戶端,.netcat 或 socat,然后先修復服務器端:

  1. 服務器:您需要尊重 from_client 以與第一個字母進行比較:
if(*from_client == 't') {

服務器返回正確的提示:

$ socat - tcp-connect:localhost:5000
t
Wed Feb  1 00:04:36 2023
  1. server: sendBuff == "Marcus Baker"是一個比較並且總是錯誤的,你只需要發送盡可能多的字節而不是整個緩沖區:
            strcpy(sendBuff, "Marcus Baker");
            send(connfd, sendBuff, strlen(sendBuff), 0);

並測試它:

n
Marcus Baker
  1. server: sendBuff == "201604543"是比較。 您必須決定是否要將其作為字符串或二進制發送,如果您想要特定編碼(小印度或大印度),則決定是否二進制。 使用二進制並在客戶端和服務器上假定相同的編碼:
            memcpy(sendBuff, &(int) { 201604543 }, sizeof(int));
            send(connfd, sendBuff, sizeof(int), 0);

結果是(注意使用od -t d4來解碼 integer 值):

socat - tcp-connect:localhost:5000 | od -t d4
i
0000000   201604543
0000004

現在我們知道服務器工作(更好)所以讓我們開始在客戶端上工作。

  1. 客戶端:客戶端連接后它執行read()但服務器正在執行recv() 客戶端應該寫入服務器,所以讓我們刪除這個塊:
    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF)
        {
            printf("\n Error : Fputs error\n");
        }
    }

    if(n < 0) {
        printf("\n Read error \n");
    }
  1. 服務器:現在,當我們發送“t”時,服務器會隨着時間做出響應,但會返回一堆 0。返回服務器,我們會看到它發送了整個緩沖區,所以讓我們解決這個問題:
            int n = snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, n);
  1. 客戶端:時間過后我們仍然得到一堆 0 所以讓我們記錄我們從服務器獲得了多少數據並只打印出來:
    printf("%s", "Letter Sent\n");
    ssize_t recvLen = recv(sockfd, recvBuff, sizeof(recvBuff), 0);
    printf("%.*s", (int) recvLen, recvBuff);

現在客戶報告:

Enter a Character (t, n, i, q): t
Letter Sent
Wed Feb  1 00:26:13 2023
  1. 客戶:我們為“i”獲得的數據看起來很奇怪:
Enter a Character (t, n, i, q): i
Letter Sent
=
 

這是因為它是二進制數據,所以我們需要對其進行解碼:

    if(*letter = 'i') {
        printf("%d", *(int *) recvBuff);
    } else {
        // ...

output 現在符合預期:

Enter a Character (t, n, i, q): i
Letter Sent
201604543
  1. 客戶:“q”打印看起來不正確:
Letter Sent
808464432

那是因為我們實際上並不期望獲得更多數據:

    printf("%s", "Letter Sent\n");
    if(*letter == 'q')
        return 0;
  1. 服務器:當客戶端發送“q”時,我們返回,但這會使套接字超時 state。最好先關閉它:
        if(*from_client == 'q') {
            close(connfd);
            return 0;
        }

這是更改后的程序:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    int sockfd, n = 0;
    char letter[1024];
    printf("Enter a Character (t, n, i, q): ");
    scanf("%c",&letter);
    char recvBuff[1024];
    struct sockaddr_in serv_addr;

    if(argc != 2) {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    }

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Error : Could not create socket \n");
        return 1;
    }

    memset(&serv_addr, '0', sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000);

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0) {
        printf("\n inet_pton error occured\n");
        return 1;
    }

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\n Error : Connect Failed \n");
        return 1;
    }

    int toServer = send(sockfd, letter, sizeof(letter), 0);
    printf("%s", "Letter Sent\n");
    if(*letter == 'q')
        return 0;
    ssize_t recvLen = recv(sockfd, recvBuff, sizeof(recvBuff), 0);
    if(*letter = 'i') {
        printf("%d", *(int *) recvBuff);
    } else {
        printf("%.*s", (int) recvLen, recvBuff);
    }
}

服務器.c:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>

int main(int argc, char *argv[]) {
    int listenfd, connfd;
    struct sockaddr_in serv_addr;

    char sendBuff[1025];
    char from_client[1025];
    time_t ticks;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000);

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    listen(listenfd, 10);

    for(;;) {
        connfd = accept(listenfd, NULL, NULL);

        recv(connfd, from_client, sizeof(from_client), 0);
        printf("%s", "Letter Recieved\n");
        if(*from_client == 't') {
            ticks = time(NULL);
            int n = snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
            write(connfd, sendBuff, n);
        }
        if(*from_client == 'n') {
            strcpy(sendBuff, "Marcus Baker");
            send(connfd, sendBuff, strlen(sendBuff), 0);
        }
        if(*from_client == 'i') {
            memcpy(sendBuff, &(int) { 201604543 }, sizeof(int));
            send(connfd, sendBuff, sizeof(int), 0);
        }
        if(*from_client == 'q') {
            return 0;
        }
        close(connfd);
        sleep(1);
    }
}
  1. (不固定)我建議您提取共享端口號並存儲在一個 header 文件中,您可以在客戶端和服務器中包含該文件。 例如:
#define SERVER_PORT 5000

然后使用該常量而不是硬編碼神奇值 5000。

  1. (不固定)審核所有調用以確保您檢查返回值並處理錯誤。 不這樣做會浪費時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM