【问题标题】:Socket TCP in linux - Client cannot insert usernamelinux中的套接字TCP - 客户端无法插入用户名
【发布时间】:2021-05-14 09:41:23
【问题描述】:

我在使用 TCP/IP 套接字实现登录/注册系统时遇到了麻烦。

所以,每当我想让用户注册时,客户端不能插入用户名,但他可以插入密码。好像跳过了一步。

这里是代码。

客户

void func(int sockfd)
{
    char username[MAX], password[MAX];
    int n, c;

    bzero(username, sizeof(username));
    printf("Enter the username : ");
    n = 0;
    while ((username[n++] = getchar()) != '\n')
        ;
    write(sockfd, username, sizeof(username));
    bzero(username, sizeof(username));

    bzero(password, sizeof(password));
    printf("Enter the password : ");
    c = 0;
    while ((password[c++] = getchar()) != '\n')
        ;
    write(sockfd, password, sizeof(password));
    bzero(username, sizeof(password));
}

...

int choice, ans;
    
func(sockfd);

bzero(buffer, 255);
n = read(sockfd, buffer, 255);
if(n < 0)
    error("Error reading from socket");
printf("Server - %s", buffer);
scanf("%d", &choice);
write(sockfd, &choice, sizeof(int));
    
if(choice == 1) {
    func(sockfd);
}


if(choice == 3) {
    printf("Session terminated\n");
    close(sockfd);
}

close(sockfd);
return 0;

服务器

void func(int newsockfd)
{
    char username[MAX], password[MAX];
    int n;

    bzero(username, MAX);
    read(newsockfd, username, sizeof(username));
    printf("From client: %s\n", username);

    bzero(password, MAX);
    read(newsockfd, password, sizeof(password));
    printf("From client pass: %s\n", password);

    while ((username[n++] = getchar()) != '\n')
        ;

    write(newsockfd, username, sizeof(username));
}

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


    func(newsockfd);

    int num1, num2, ans, choice;

    n = write(newsockfd, "Benvenuto, inserisci una scelta: \n1. Registrazione\n2. Login\n3. Esci\n", strlen("Benvenuto, inserisci una scelta: \n1. Registrazione\n2. Login\n3. Esci\n"));
    if(n < 0) error("Error writing to socket");
    read(newsockfd, &choice, sizeof(int));

    switch(choice) {
        case 1:
            func(newsockfd);
            break;
        
        case 2:
            break;

        case 3:
            close(newsockfd);
            close(sockfd);
    }
    
    close(newsockfd);
    close(sockfd);
    return 0;
}

这是一个例子:

【问题讨论】:

  • 您忽略了read() 返回的值。你不能那样写正确的网络程序。它可以是 -1,也可以是 0,或者它可以是 1 和您提供的长度之间的任何值,两者都包括在内。更正您的代码并重新测试。
  • 感谢您的回答。我按照您的建议修复了代码,但程序仍然损坏。函数 func(....) 在切换之前工作正常.. 但是每当我在案例 1 中插入 func(.....) 时,客户端就无法插入用户名。

标签: sockets tcp tcpclient serversocket


【解决方案1】:

忽略提供的代码不是完整的代码,客户端和服务器甚至不是使用相同的协议,所以你当然会遇到问题。

客户端甚至在收到服务器的初始提示之前就将用户名和密码发送到服务器。

服务器期望客户端的第一个输入是用户对提示的选择,但客户端首先发送用户名,因此服务器接收的前几个字符将被误解为整数。

当服务器确实希望收到用户名和密码时,它会发回用户名,客户端不会读取。

您还完全忽略了read()write() 的返回值。而且您也没有正确处理收到的字符串。

话虽如此,请尝试更多类似的东西:

共享

int sendAll(int sockfd, void *buf, size_t len)
{
    char *pbuf = (char*) buf;
    int n;

    while (len > 0) {
        n = send(sockfd, pbuf, len, 0);
        if (n < 0) return n;
        pbuf += n;
        len -= n;
    }

    return 0;
}

int recvAll(int sockfd, void *buf, size_t len)
{
    char *pbuf = (char*) buf;
    int n;

    while (len > 0) {
        n = recv(sockfd, pbuf, len, 0);
        if (n <= 0) return n;
        pbuf += n;
        len -= n;
    }

    return 1;
}

int sendInt32(int sockfd, int32_t value)
{
    value = htonl(value);
    return sendAll(sockfd, &value, sizeof(value));
}

int recvInt32(int sockfd, int32_t *value)
{
    int n = recvAll(sockfd, value, sizeof(*value));
    if (n == 1) *value = ntohl(*value);
    return n;
}

int sendStr(int sockfd, const char *str)
{
    int len = strlen(str);
    int n = sendInt32(sockfd, len);
    if (n == 0) n = sendAll(sockfd, str, len);
    return n;
}

int recvStr(int sockfd, char **str)
{
    *str = NULL;

    int32_t len;
    int n = recvInt32(sockfd, &len);
    if (n <= 0) return n;

    *str = malloc(len + 1);
    if (*str == NULL) return -1;

    n = recvAll(sockfd, *str, len);
    if (n <= 0) {
        free(*str);
        *str = NULL;
        return n;
    }

    (*str)[len] = '\0';
    return 1;
}

客户

void func(int sockfd)
{
    char input[MAX+1];
    int n, c;

    printf("Enter the username : ");
    n = 0;
    while ((n < MAX) && ((c = getchar()) != EOF) && (c != '\n')) {
        input[n++] = (char) c;
    }
    input[n] = '\0';

    if (sendStr(sockfd, input) < 0)
        error("Error writing to socket");

    printf("Enter the password : ");
    n = 0;
    while ((n < MAX) && ((c = getchar()) != EOF) && (c != '\n')) {
        input[n++] = (char) c;
    }
    input[n] = '\0';

    if (sendStr(sockfd, input) < 0)
        error("Error writing to socket");

    char *ans;
    if (recvStr(sockfd, &ans) <= 0)
        error("Error reading from socket");

    printf("Server - %s: ", ans);
    free(ans);
}

int main() {
    int sockfd, choice;
    char *str;
    
    // connect to server...
    sockfd = ...;

    if (recvStr(sockfd, &str) <= 0)
        error("Error reading from socket");

    printf("Server - %s", str);
    free(str);

    scanf("%d", &choice);

    if (sendInt32(sockfd, choice) < 0)
        error("Error writing to socket");
    
    switch (choice) {
        case 1:
        case 2:
            func(sockfd);
            break;

        case 3:
            printf("Session terminated\n");
            break;
    }

    close(sockfd);
    return 0;
}

服务器

void func(int sockfd, int choice)
{
    char *input;

    if (recvStr(sockfd, &input) <= 0)
        error("Error reading from socket");

    printf("From client user: %s\n", input);
    free(input);

    if (recvStr(sockfd, &input) <= 0)
        error("Error reading from socket");

    printf("From client pass: %s\n", input);
    free(input);

    char *ans = (choice == 1) ? "Registered" : "Logged in";
    if (sendStr(sockfd, ans) < 0)
        error("Error writing to socket");
}

int main() {

    int sockfd, clientsockfd, n;
    int32_t choice;

    // setup listening socket ...
    sockfd = ...;

    // accept client ...
    clientsockfd = ...;

    if (SendStr(clientsockfd, "Benvenuto, inserisci una scelta: \n1. Registrazione\n2. Login\n3. Esci\n") < 0)
        error("Error writing to socket");

    if (recvInt32(clientsockfd, &choice) < 0)
        error("Error reading from socket");

    switch (choice) {
        case 1:
        case 2:
            func(clientsockfd, choice);
            break;

        case 3:
            close(clientsockfd);
            break;
    }
    
    close(sockfd);
    return 0;
}

【讨论】:

  • 感谢您的回答。我使用了您的代码,但问题仍然存在
  • @JonathanQuaranta 那么您要么没有将我的示例课程正确地应用到您的代码中,要么您正在做其他我们看不到的错误。当客户端和套接字使用相同的协议并且彼此同步时,我给你的代码应该可以工作。
【解决方案2】:

a) 你能 printf("choice: %d\n",choice);
b) 我有问题要查看套接字是否被您的第一个函数调用阻塞
c) 最重要的是——我们必须关注一个事实,即您尝试发送序列化数据 (int)——这完全不同于发送纯文本。谷歌搜索:“网络字​​节序”:

 //client 
 uint32_t choice;
 choice = htons(choice);
 write(sockfd, &choice, sizeof(choice));

//server
uint32_t choice;
read(newsockfd, &choice, sizeof(uint32_t));
choice = ntohs(choice);

switch(choice);

【讨论】:

  • 感谢您抽出宝贵时间回复我。我打印了变量选择,结果是这样的:如果我按 1,它会打印 1。与 2 相同,等等。我按照建议尝试了您的选项 (c),这次选择变成了 156。我认为问题应该是 ( b),但是如何阻塞套接字?
  • 我假设——据我所知——当你调用你的func()(从 main 中的第一个调用开始)时,套接字会被阻塞。您可以尝试在 func() 函数中关闭套接字吗?您还可以将代码更新到您当前的工作版本吗?
猜你喜欢
  • 2012-03-29
  • 2013-10-24
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-15
相关资源
最近更新 更多