C Socket recv()奇怪的字符

时间:2017-04-02 20:58:53

标签: c windows sockets

所以我主要坚持使用套接字的MAC / Linux,这一切都运行正常,所以我试图将我的Windows套接字放在一边,这可能是因为我做错了而且这样做是错误的。整个问题,但我现在试图解决的问题是控制台在服务器发送的实际字符串后打印随机字符。 Server.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;
}

Client.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;
}

我输入&#34;你好&#34;进入服务器控制台和客户端控制台recv()s / Prints 由于我无法通过控制台生成C&amp; P而只是有了它的图片 Console Output

更新了许多我所做的修复它的null终结符的问题是switch

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

在server.c到

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

2 个答案:

答案 0 :(得分:3)

很难确切地说出为什么你会遇到这种完全不稳定的行为,因为你同时滥用了几件事,所以结果真的很奇怪。

首先,套接字是流,它们不是消息传递机制。这意味着套接字没有&#34;消息的概念&#34;您正试图发送和接收。接收端的套接字无论你在发送端写了10个字节都没有任何线索。因此,如果要使用套接字发送消息,则必须在流的顶部实现消息传递协议。

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

然后,由于套接字是流,因此您必须注意每次从套接字读取多少字节。仅仅因为你要求10个字节,这并不意味着你将获得10个字节。如果要求10个字节并且接收的字节少于10个,则必须重复调用,以读取更多字节。 recv()函数不会返回任何&#34;读者&#34;。它返回成功读取的字节数。并且它不应存储在从未检查过的变量中。应将其考虑在内,以便您知道自己是否收到了预期的完整信息。

另外,不要忘记asciiz null-char终止符。发送字符串时,可以将消息的长度视为字符串的strlen()。但是当您收到该字符串时,它不会被null-char终止,因此如果没有先向printf()附加\0,您就无法继续将其提供给printf()。如果省略null-char终止符,则[snippet slug=my-example-html-snippet lang=html] 将打印您的字符串,然后是接收缓冲区中已经发生的任何垃圾。

答案 1 :(得分:0)

常见问题。您忽略了recv()返回的值:

reader = recv(sock, message, 2000, 0);
fprintf(stdout, "%s", message)

应该是

reader = recv(sock, message, 2000, 0);
if (reader == -1)  // error
{
    perror("recv)"); // at least
    break; // out of the read loop and close the socket
}
else if (reader == 0) // EOS: peer has closed the connection
    break;
else
    fprintf(stdout, "%.*s", reader, message);