c 中的 UDP:以块形式保存接收到的数据时,额外的字符被添加到文件中

发布于 2024-10-05 12:41:35 字数 2882 浏览 0 评论 0原文

我正在尝试让一个简单的发送和接收 UDP 程序正常工作,但在保存接收到的数据时遇到了一些麻烦。据我所知,数据正在正确发送和接收,因为我已将其打印在两端。在我将数据写入文件之前(如果我只是打印出接收到的块),它没有任何额外的字符,所以我有点不知道它们来自哪里。

当我将接收到的数据的每个块附加到文件时,它会添加一个“^P^B^GÐ^?”在写入每个块之后。例如,其中一个块以“我们,因此^P^B^GÐ^?”结尾,而不是“我们,因此,”。

感谢任何帮助,提前致谢。


更新:

我似乎已经让事情工作得更好了,我现在遇到了一个问题,即将每个块的第一个字符替换为空字符,例如:

“^@N CONGRESS,1776 年 7 月 4 日。 ”而不是“1776 年 7 月 4 日国会”。

它对收到的每个块的第一个字符执行此操作,我尝试了多个调试打印语句,但似乎无法弄清楚问题是什么。

这是我的接收和发送功能:

void receiveFile() {
int addr_len, bytesRead;
char recvData[BUFSIZE]; // Buffer to store received data
struct sockaddr_in server_addr, client_addr;

// Set up struct to receive data from our port and address
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);

addr_len = sizeof (struct sockaddr);

printf("\nWaiting for data on port %d\n", port);


//Keep reading data from the socket
while (1) {
    FILE *fp;
    fp=fopen("dummyfile.txt", "ab");

    memset(recvData, 0, BUFSIZE);
    bytesRead = recvfrom(sock, recvData, BUFSIZE, 0,
            (struct sockaddr *) &client_addr, &addr_len);
    int x;
    for(x = 0; x < bytesRead; x++) {
        fputc(recvData[x], fp);
    }

    // Print out who we're receiving from and what we're recieving
    printf("Receiving data from %s : %d\n", inet_ntoa(client_addr.sin_addr),
            ntohs(client_addr.sin_port));

    fclose(fp);
}}

这是发送功能:

void sendFile() {
// Announce who we're sending data to
if(DEBUG) { printf("\nSending %s to %s:%d\n", filename, address, port); }

// Open file
FILE * file = fopen(filename, "rb");
if (file == NULL) {
  perror("Invalid File\n");
  exit(1);
}

// Get size of the file
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
rewind(file);

int curPos = 0;
int dataSize = 0;

while(curPos < filesize) {

    struct sockaddr_in server_addr; 
    struct hostent *recvr;

    char sendData[BUFSIZE]; // stores message to be sent
    memset(sendData, 0, BUFSIZE);

    int byte, i;
    for(i = 0; i < BUFSIZE; i++){
        if((filesize - curPos) > 0) {
            byte = fgetc(file);
            sendData[i] = byte;
            curPos++;
            dataSize++;
        }
        else { break; }
    }

    recvr = gethostbyname(address);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr = *((struct in_addr *) recvr->h_addr);
    bzero(&(server_addr.sin_zero), 8);

    if(DEBUG) {
        char tempData[1201];
        strncpy(tempData, sendData, 1200);
        tempData[1201] ='\0';
        printf("%s\n\n\n\n\n", tempData);
    }

    sendto(sock, sendData, dataSize, 0,
            (struct sockaddr *) &server_addr, sizeof (struct sockaddr));
    dataSize = 0;
}

fclose(file);}

I'm trying to get a simple send and receive UDP program working, but I'm having a bit of trouble with saving the received data. As far as I can tell the data is being sent and received properly, as I've printed it out on both ends. Before I write the data to the file (if I just print out the received chunk) it doesn't have any extra characters, so I'm a bit lost as to where they are coming from.

When I append each chunk of received data to the file it adds a "^P^B^GÐ^?" after every chunk written. for example one of the chunks ended with "We, therefore^P^B^GÐ^?," instead of "We, therefore,".

Any help is appreciated, thanks in advance.


UPDATE:

I've seemed to have gotten things working semi-better, I'm now having an issue with it replacing the first character of every chunk with a null character, for example:

"^@N CONGRESS, July 4, 1776." instead of "IN CONGRESS, July 4, 1776."

It's doing this for the first char of every chunk received, I've tried multiple debug print statements but can't seem to figure out what the issue is.

Here is my Receive and Send functions:

void receiveFile() {
int addr_len, bytesRead;
char recvData[BUFSIZE]; // Buffer to store received data
struct sockaddr_in server_addr, client_addr;

// Set up struct to receive data from our port and address
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);

addr_len = sizeof (struct sockaddr);

printf("\nWaiting for data on port %d\n", port);


//Keep reading data from the socket
while (1) {
    FILE *fp;
    fp=fopen("dummyfile.txt", "ab");

    memset(recvData, 0, BUFSIZE);
    bytesRead = recvfrom(sock, recvData, BUFSIZE, 0,
            (struct sockaddr *) &client_addr, &addr_len);
    int x;
    for(x = 0; x < bytesRead; x++) {
        fputc(recvData[x], fp);
    }

    // Print out who we're receiving from and what we're recieving
    printf("Receiving data from %s : %d\n", inet_ntoa(client_addr.sin_addr),
            ntohs(client_addr.sin_port));

    fclose(fp);
}}

Here is the Send Function:

void sendFile() {
// Announce who we're sending data to
if(DEBUG) { printf("\nSending %s to %s:%d\n", filename, address, port); }

// Open file
FILE * file = fopen(filename, "rb");
if (file == NULL) {
  perror("Invalid File\n");
  exit(1);
}

// Get size of the file
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
rewind(file);

int curPos = 0;
int dataSize = 0;

while(curPos < filesize) {

    struct sockaddr_in server_addr; 
    struct hostent *recvr;

    char sendData[BUFSIZE]; // stores message to be sent
    memset(sendData, 0, BUFSIZE);

    int byte, i;
    for(i = 0; i < BUFSIZE; i++){
        if((filesize - curPos) > 0) {
            byte = fgetc(file);
            sendData[i] = byte;
            curPos++;
            dataSize++;
        }
        else { break; }
    }

    recvr = gethostbyname(address);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr = *((struct in_addr *) recvr->h_addr);
    bzero(&(server_addr.sin_zero), 8);

    if(DEBUG) {
        char tempData[1201];
        strncpy(tempData, sendData, 1200);
        tempData[1201] ='\0';
        printf("%s\n\n\n\n\n", tempData);
    }

    sendto(sock, sendData, dataSize, 0,
            (struct sockaddr *) &server_addr, sizeof (struct sockaddr));
    dataSize = 0;
}

fclose(file);}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

忆沫 2024-10-12 12:41:35

将打印更改为时会发生什么:

fprintf(fp, "%.*s", bytesRead, recvData);

保证 recvfrom( ) 不会 null 终止您的消息;您必须自己传输空终止符。


我不知道你的残留问题是什么。我有以下工作来完成连续工作的程序。我已经仔细检查了保存的文件中是否有 NUL,没有任何问题。

我将它们运行为:

./recv & sleep 1; ./send; kill %1

recv.c

#include "posixver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in */
#include <arpa/inet.h>  /* inet_ntoa() */
#include "stderr.h"

static void receiveFile(int sock, int port, char *filename)
{
    //Keep reading data from the socket
    FILE *fp = fopen(filename, "ab");
    if (fp == 0)
        err_syserr("failed to open file %s", filename);

    printf("\nWaiting for data on port %d\n", port);
    while (1)
    {
        char recvData[BUFSIZ]; // Buffer to store received data
        struct sockaddr_storage addr;
        struct sockaddr_in *client_addr = (struct sockaddr_in *)&addr;
        memset(recvData, 0, sizeof(recvData));
        socklen_t addr_len = sizeof (struct sockaddr_storage);
        int bytesRead = recvfrom(sock, recvData, sizeof(recvData), 0,
                (struct sockaddr *) &client_addr, &addr_len);
        if (bytesRead < 0)
            err_syserr("Failed to read from socket");
        err_remark("Read %d bytes\n", bytesRead);
        for (int x = 0; x < bytesRead; x++)
        {
            fputc(recvData[x], fp);
        }
        fflush(fp);

        // Print out who we're receiving from and what we're receiving
        //char *rem_host = inet_ntoa(client_addr->sin_addr);
        //int   rem_port = ntohs(client_addr->sin_port);
        //printf("Receiving %d bytes from %s:%d\n", bytesRead, rem_host ? rem_host : "<unknown>", rem_port);
    }
    fclose(fp);
}

int main(int argc, char **argv)
{
    int fd;
    struct sockaddr_storage addr;
    struct sockaddr_in *server_addr = (struct sockaddr_in *)&addr;

    memset(&addr, 0, sizeof(addr));
    server_addr->sin_family = AF_INET;
    server_addr->sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr->sin_port = htons(5190);

    err_setarg0(argv[0]);
    if (argc > 1)
        err_usage("");
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        err_syserr("Failed to open DGRAM socket");
    if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
        err_syserr("Failed to bind DGRAM socket");
    receiveFile(fd, 5190, "dummy.text");

    return(0);
}

send.c

#include "posixver.h"
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "stderr.h"

#define bzero(b,len) (memset((b), '\0', (len)), (void)0)

enum { DEBUG = 1 };

static void sendFile(int sock, const char *filename, char *address, int port)
{
    // Announce who we're sending data to
    if (DEBUG)
        printf("\nSending %s to %s:%d\n", filename, address, port);

    // Open file
    FILE * file = fopen(filename, "rb");
    if (file == 0)
        err_syserr("Failed to open file %s", filename);

    // Get size of the file
    fseek(file, 0, SEEK_END);
    int filesize = ftell(file);
    rewind(file);

    int curPos = 0;
    int dataSize = 0;

    while (curPos < filesize)
    {
        struct sockaddr_in server_addr; 
        struct hostent *recvr;
        char sendData[BUFSIZ]; // stores message to be sent
        memset(sendData, 0, BUFSIZ);

        int byte, i;
        for (i = 0; i < BUFSIZ; i++){
            if ((filesize - curPos) > 0) {
                byte = fgetc(file);
                sendData[i] = byte;
                curPos++;
                dataSize++;
            }
            else
                break;
        }

        recvr = gethostbyname(address);
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        server_addr.sin_addr = *((struct in_addr *) recvr->h_addr_list[0]);
        bzero(&(server_addr.sin_zero), 8);

        if(DEBUG) {
            char tempData[1201];
            strncpy(tempData, sendData, 1200);
            tempData[1201] ='\0';
            printf("SEND:\n%s\n\n\n", tempData);
        }

        if (sendto(sock, sendData, dataSize, 0,
                (struct sockaddr *) &server_addr, sizeof (struct sockaddr)) < 0)
            err_syserr("Failed to send %d bytes\n", dataSize);
        dataSize = 0;
    }

    fclose(file);
}

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

    err_setarg0(argv[0]);
    if (argc > 1)
        err_usage("");
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        err_syserr("Failed to open DGRAM socket");
    sendFile(fd, "/etc/passwd", "localhost", 5190);

    return(0);
}

posixver.h

#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H

/*
** Include this file before including system headers.  By default, with
** C99 support from the compiler, it requests POSIX 2001 support.  With
** C89 support only, it requests POSIX 1997 support.  Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/

/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */

#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600   /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
#else
#define _XOPEN_SOURCE 500   /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */

#endif /* JLSS_ID_POSIXVER_H */

stderr.c和stderr.h

实际上,根本不标准,除了在我的代码中。使用的函数具有以下声明:

extern void err_setarg0(const char *argv0);
extern void err_error(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);
extern void err_syserr(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_usage(const char *usestr) NORETURN();

第一个记录程序名称。第二个报告错误消息并退出;第三个上报消息并返回;第四个报告错误消息并添加来自“errno”和“strerror()”的错误信息(如果有的话);最后报告如何使用该程序 - 在本例中,程序不接受任何参数。完整的源代码(相当大)可以从 IIUG Software 站点获取,作为 SQLCMD 包的一部分,以及我也在那里提交的各种其他程序。

What happens when you change the printing to:

fprintf(fp, "%.*s", bytesRead, recvData);

There is a guarantee that recvfrom() will not null terminate your messages; you would have to transmit the null terminator yourself.


I can't tell what your residual problem is. I have the following to complete programs working back to back. I've scrutinized the saved file for NULs with no problem.

I ran them as:

./recv & sleep 1; ./send; kill %1

recv.c

#include "posixver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in */
#include <arpa/inet.h>  /* inet_ntoa() */
#include "stderr.h"

static void receiveFile(int sock, int port, char *filename)
{
    //Keep reading data from the socket
    FILE *fp = fopen(filename, "ab");
    if (fp == 0)
        err_syserr("failed to open file %s", filename);

    printf("\nWaiting for data on port %d\n", port);
    while (1)
    {
        char recvData[BUFSIZ]; // Buffer to store received data
        struct sockaddr_storage addr;
        struct sockaddr_in *client_addr = (struct sockaddr_in *)&addr;
        memset(recvData, 0, sizeof(recvData));
        socklen_t addr_len = sizeof (struct sockaddr_storage);
        int bytesRead = recvfrom(sock, recvData, sizeof(recvData), 0,
                (struct sockaddr *) &client_addr, &addr_len);
        if (bytesRead < 0)
            err_syserr("Failed to read from socket");
        err_remark("Read %d bytes\n", bytesRead);
        for (int x = 0; x < bytesRead; x++)
        {
            fputc(recvData[x], fp);
        }
        fflush(fp);

        // Print out who we're receiving from and what we're receiving
        //char *rem_host = inet_ntoa(client_addr->sin_addr);
        //int   rem_port = ntohs(client_addr->sin_port);
        //printf("Receiving %d bytes from %s:%d\n", bytesRead, rem_host ? rem_host : "<unknown>", rem_port);
    }
    fclose(fp);
}

int main(int argc, char **argv)
{
    int fd;
    struct sockaddr_storage addr;
    struct sockaddr_in *server_addr = (struct sockaddr_in *)&addr;

    memset(&addr, 0, sizeof(addr));
    server_addr->sin_family = AF_INET;
    server_addr->sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr->sin_port = htons(5190);

    err_setarg0(argv[0]);
    if (argc > 1)
        err_usage("");
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        err_syserr("Failed to open DGRAM socket");
    if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
        err_syserr("Failed to bind DGRAM socket");
    receiveFile(fd, 5190, "dummy.text");

    return(0);
}

send.c

#include "posixver.h"
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "stderr.h"

#define bzero(b,len) (memset((b), '\0', (len)), (void)0)

enum { DEBUG = 1 };

static void sendFile(int sock, const char *filename, char *address, int port)
{
    // Announce who we're sending data to
    if (DEBUG)
        printf("\nSending %s to %s:%d\n", filename, address, port);

    // Open file
    FILE * file = fopen(filename, "rb");
    if (file == 0)
        err_syserr("Failed to open file %s", filename);

    // Get size of the file
    fseek(file, 0, SEEK_END);
    int filesize = ftell(file);
    rewind(file);

    int curPos = 0;
    int dataSize = 0;

    while (curPos < filesize)
    {
        struct sockaddr_in server_addr; 
        struct hostent *recvr;
        char sendData[BUFSIZ]; // stores message to be sent
        memset(sendData, 0, BUFSIZ);

        int byte, i;
        for (i = 0; i < BUFSIZ; i++){
            if ((filesize - curPos) > 0) {
                byte = fgetc(file);
                sendData[i] = byte;
                curPos++;
                dataSize++;
            }
            else
                break;
        }

        recvr = gethostbyname(address);
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        server_addr.sin_addr = *((struct in_addr *) recvr->h_addr_list[0]);
        bzero(&(server_addr.sin_zero), 8);

        if(DEBUG) {
            char tempData[1201];
            strncpy(tempData, sendData, 1200);
            tempData[1201] ='\0';
            printf("SEND:\n%s\n\n\n", tempData);
        }

        if (sendto(sock, sendData, dataSize, 0,
                (struct sockaddr *) &server_addr, sizeof (struct sockaddr)) < 0)
            err_syserr("Failed to send %d bytes\n", dataSize);
        dataSize = 0;
    }

    fclose(file);
}

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

    err_setarg0(argv[0]);
    if (argc > 1)
        err_usage("");
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        err_syserr("Failed to open DGRAM socket");
    sendFile(fd, "/etc/passwd", "localhost", 5190);

    return(0);
}

posixver.h

#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H

/*
** Include this file before including system headers.  By default, with
** C99 support from the compiler, it requests POSIX 2001 support.  With
** C89 support only, it requests POSIX 1997 support.  Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/

/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */

#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600   /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
#else
#define _XOPEN_SOURCE 500   /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */

#endif /* JLSS_ID_POSIXVER_H */

stderr.c and stderr.h

Actually, not standard at all, except in my code. The functions used have the declarations:

extern void err_setarg0(const char *argv0);
extern void err_error(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);
extern void err_syserr(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_usage(const char *usestr) NORETURN();

The first records the program name. The second reports an error message and exits; the third reports a message and returns; the fourth reports an error message and adds error information from 'errno' and 'strerror()' if there is any to use; the last reports on how to use the program - in this case, the programs accept no arguments. The full source code (quite large) is available from the IIUG Software site as part of the SQLCMD package available there, and various other programs that I've also submitted there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文