c中的UDP:将接收到的数据保存为块时,会向文件中添加额外字符
我试图让一个简单的发送和接收UDP程序工作,但在保存接收到的数据时遇到了一些问题。据我所知,数据被正确地发送和接收,因为我已经在两端打印出来了。在我将数据写入文件之前(如果我只是打印出接收到的块),它没有任何额外的字符,所以我有点不知道它们来自哪里 当我将接收到的每个数据块追加到文件中时,它会在写入的每个数据块之后添加一个“^p^B^GÐ^”。例如,其中一个词块以“We,Thouse^P^B^GÐ^?”而不是“We,Thouse”结尾 感谢您的帮助,提前谢谢c中的UDP:将接收到的数据保存为块时,会向文件中添加额外字符,c,file,file-io,udp,printf,C,File,File Io,Udp,Printf,我试图让一个简单的发送和接收UDP程序工作,但在保存接收到的数据时遇到了一些问题。据我所知,数据被正确地发送和接收,因为我已经在两端打印出来了。在我将数据写入文件之前(如果我只是打印出接收到的块),它没有任何额外的字符,所以我有点不知道它们来自哪里 当我将接收到的每个数据块追加到文件中时,它会在写入的每个数据块之后添加一个“^p^B^GÐ^”。例如,其中一个词块以“We,Thouse^P^B^GÐ^?”而不是“We,Thouse”结尾 感谢您的帮助,提前谢谢 更新: 我似乎已经让事情变得更好了
更新: 我似乎已经让事情变得更好了,我现在遇到了一个问题,用空字符替换每个块的第一个字符,例如: “国会,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 receiveFile(){
内部地址,字节读取;
char recvData[BUFSIZE];//用于存储接收数据的缓冲区
服务器地址、客户端地址中的结构sockaddr\u;
//设置struct以从端口和地址接收数据
服务器地址sin家庭=AF网络;
服务器地址sin\u端口=htons(端口);
server\u addr.sin\u addr.s\u addr=INADDR\u ANY;
bzero(&(服务器地址sin_zero),8);
addr_len=sizeof(结构sockaddr);
printf(“\n正在等待端口%d上的数据,\n”,端口);
//保持从套接字读取数据
而(1){
文件*fp;
fp=fopen(“dummyfile.txt”、“ab”);
memset(recvData,0,BUFSIZE);
bytesRead=recvfrom(sock、recvData、BUFSIZE、0、,
(结构sockaddr*)和客户机地址和地址;
int x;
对于(x=0;x
以下是发送功能:
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);}
void sendFile(){
//宣布我们向谁发送数据
if(DEBUG){printf(“\n将%s发送到%s:%d\n”,文件名、地址、端口);}
//打开文件
FILE*FILE=fopen(文件名,“rb”);
if(file==NULL){
perror(“无效文件\n”);
出口(1);
}
//获取文件的大小
fseek(文件,0,SEEK_END);
int filesize=ftell(文件);
倒带(文件);
int curPos=0;
int-dataSize=0;
while(curPos0){
字节=fgetc(文件);
sendData[i]=字节;
curPos++;
dataSize++;
}
else{break;}
}
recvr=gethostbyname(地址);
服务器地址sin家庭=AF网络;
服务器地址sin\u端口=htons(端口);
服务器地址sin\u addr=*((地址中的结构)recvr->h\u addr);
bzero(&(服务器地址sin_zero),8);
如果(调试){
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*)和服务器地址,sizeof(struct sockaddr));
dataSize=0;
}
fclose(文件);}
将打印更改为:
fprintf(fp, "%.*s", bytesRead, recvData);
有一个保证,将不会空终止您的邮件;您必须自己传输空终止符
我不知道你还有什么问题。我有以下内容来完成背靠背工作的程序。我仔细检查了NUL保存的文件,没有问题 我把它们当作:
./recv & sleep 1; ./send; kill %1
记录c
标准c和标准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()”的错误信息(如果有);最后报告如何使用该程序-在本例中,程序不接受任何参数。完整的源代码(相当大)作为SQLCMD软件包的一部分在网站上提供,我也在网站上提交了其他各种程序。Jonathan,他正在调用
memset()
在调用recv()
之前将接收缓冲区归零;因此,缓冲区将被NUL终止。不一定,@Steve:被调用的函数不会写入超出传递的缓冲区边界的内容,但不会承诺在返回数据后不会留下额外的数据。我不确定这是否是问题所在——这就是为什么我的回答是一个问题。但我认为,确保接收者只处理告知其可用的数据是值得的。如果您发送的消息长度为BUFSIZE,那么接收缓冲区将不会被NUL终止,并且除非您将缓冲区的大小增加1,否则您将无法在接收端对其进行NUL终止。嗯,似乎出现了一个新问题,在实际服务器上运行时,它不会写入文件,它只会创建一个空文件。在本地主机上运行时,它会完美地发送文件。我已将目录中的权限设置为755,但它似乎仍然不起作用。@AnthonyJK:因为您的代码没有检查文件是否打开正常,所以您无法确定发生了什么。另外,您确定知道哪个目录是服务器的当前目录吗?您是否忘记了发送函数的文件名、地址和端口参数?或者它们真的是全局变量?发送循环不起作用
#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);
}
#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 */
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();