C Socket recv()ing 奇怪的字符

标签 c windows sockets

所以我主要坚持使用带有套接字的 MAC/Linux 并且一切正常,所以我尝试在某种程度上关闭我的 Windows 套接字,也许我这样做是错误的,这就是整个问题,但问题我现在正在尝试修复的是控制台在服务器发送的实际字符串之后打印随机字符。 服务器.c

#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#include "stdafx.h"
#include <conio.h>
#include <io.h>
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)  
#pragma comment(lib,"ws2_32.lib") //Winsock Library

char message[4040];
int main()
{
    WSADATA wsa;
    SOCKET sock, newsock;
    int c;
    struct sockaddr_in server, client;
    char smesg[155];
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }

    printf("Initialised.\n");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(3939);

    //bind
    if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
        printf("Bind failed! Error Code: %d", WSAGetLastError());
    }
    puts("Binded!");
    printf("\nNow Listening...\n");
    listen(sock, 1);
    //Accept!
    c = sizeof(struct sockaddr_in);
    newsock = accept(sock, (struct sockaddr *)&client, &c);
    if (newsock == INVALID_SOCKET) {
        printf("Couldn't Accept connection!");
    }
    printf("Accepted Connection!\n");
        //char *client_ip = inet_ntoa(client.sin_addr);
        //int client_port = ntohs(client.sin_port);
        while (1) {
            printf("Command: ");
            fgets(smesg, 4040, stdin);
            send(newsock, smesg, strlen(smesg), 0);
            bzero(smesg, sizeof(smesg));
            //memset(0, smesg, 4040);
        }
    return 0;
}

客户端.c

#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#include "stdafx.h"
#include <conio.h>
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)  
#pragma comment(lib,"ws2_32.lib") //Winsock Library

int main(int argc, char *argv[])
{
    int reader;
    WSADATA wsa;
    SOCKET sock;
    struct sockaddr_in server;
    char message[2000];
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }

    printf("Initialised.\n");


    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");

    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons(3939);

    //Connect
    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
        puts("Connect Error");
        return 1;
    }
    puts("Connected\n");
    while (1) {
        //memset(0, message, 4040);
        reader = recv(sock, message, 2000, 0);
        fprintf(stdout, "%s", message);
        bzero(message, 2000);
    }
    return 0;
}

我在服务器控制台和客户端控制台中键入“Hello”recv()s/Prints 由于我无法从控制台进行 C&P,所以只能用它的图片代替 Console Output

更新许多人发布的空终止符问题,我修复它的方法是 switch

        printf("Command: ");
        fgets(smesg, 155, stdin);

在server.c中

        bzero(smesg, sizeof(smesg));
        printf("Command: ");
        fgets(smesg, 155, stdin);
        strcat(smesg, "\0");

最佳答案

真的很难说清楚您为什么会遇到这种不稳定的行为,因为您同时误用了几样东西,因此可能会发生非常奇怪的事情。

首先,套接字是流,它们不是消息传递机制。这意味着套接字没有您尝试发送和接收的“消息”的概念。接收端的套接字根本不知道你在发送端写了 10 个字节。所以,如果你想使用套接字发送消息,那么你必须在流之上实现一个消息传递协议(protocol)。

在流协议(protocol)之上的消息传递协议(protocol)的最简单版本是在每条消息前加上消息的长度。所以:在发送端,首先将消息的长度写入套接字,然后写入消息本身。在阅读结束时,首先阅读长度,然后阅读消息。长度是固定的字节数(通常为 4 个字节),因此您始终知道要读/写的确切字节数。

然后,由于套接字是流,所以你必须注意每次从套接字中到底读取了多少字节。仅仅因为您请求 10 个字节并不意味着您将收到 10 个字节。如果您请求 10 个字节,而您收到的少于 10 个字节,那么您必须重复调用以读取更多字节。 recv() 函数不返回任何“读者”。它返回成功读取的字节数。并且它不会存储在以后永远不会检查的变量中。将其考虑在内,以便您知道是否收到了您期望的完整消息。

另外,不要忘记 asciiz 空字符终止符。发送字符串时,可以将消息的长度视为字符串的 strlen()。但是当您收到该字符串时,它不会以 null-char 终止,因此您不能继续将其提供给 printf() 而不先向其附加 \0。如果您省略空字符终止符,则 printf() 将打印您的字符串,然后打印您的接收缓冲区中已经存在的任何垃圾。

关于C Socket recv()ing 奇怪的字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43173475/

相关文章:

windows - 在Web应用程序和 native 应用程序之间组织安全通道

linux - 使用 rtnetlink 套接字在 linux 路由表中安装新路由

c# - 如何以编程方式读取 Windows 操作系统中 SQLite 数据库的内容?

c - 动态二维数组,无内存

c - GTK中静态编译如何处理FileChooser

c - 如何将文本文件实现为链表?

c++ - C++无法使用cygwin链接到Boost库

c - C 中的套接字问题(函数接受)

linux - 为什么一个HTTP请求请求是在第一个ack包之后发送的?

c - 有符号数与无符号数