【问题标题】:Not getting the exact data at server sent from client [closed]未在服务器上获取从客户端发送的确切数据[关闭]
【发布时间】:2015-10-11 05:01:30
【问题描述】:

我正在编写一个客户端/服务器系统,其中客户端将记录从客户端发送到服务器。我试图将数据表示为struct,但我在服务器端没有成功recv()struct

这是我的代码:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

#pragma pack(1)
struct emp
{
    int id;
    char *name;
} emp1, emp3;
#pragma pack(0)

int main(int argc, char *argv[])
{
    int sockfd = 0, n = 0;
    char recvBuff[1024];

    struct sockaddr_in serv_addr; 

    memset(recvBuff, '0', sizeof(recvBuff));
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000); 
    serv_addr.sin_addr = inet_addr("192.168.0.105");

    if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
       printf("\n Error : Connect Failed \n");
       return 1;
    } 

    emp1 = (struct emp *) malloc(sizeof(struct emp));
    emp1.name = (char *) malloc((size)*(sizeof(char)));
    printf("Enter name of employee : ");
    scanf(" %[^\n]s", emp1.name);
    printf("Enter emp id : ");
    scanf(" %d", &emp1.id);
    unsigned char *data = (unsigned char*) malloc(sizeof(regn));
    memcpy(data, &regn, sizeof(regn));
    sendto(sockfd, data, sizeof(emp1), 0, (SOCKADDR *) &serv_addr,
            sizeof(serv_addr));

    close(sockfd);
}

而我的服务器是这样的

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>

struct emp
{
    int id;
    char *name;
} emp1, emp3; 

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 
    FILE *fp, *fp1;
    char recvBuf[1025];

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 
    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

    if(recvfrom(sd, recvBuf, recvBufSize, 0,
            (struct sockaddr *) &clientAddr, &len) < 0)
    {
        printf("Error receiving message from client\n");
    }
    else
    {
       printf("Message received:%s\n", recvBuf);
       printf("Size :%d\n", strlen(recvBuf));
       memcpy(&emp1, recvBuf, sizeof(emp));
       printf("name:%s\n", emp1.name );
       printf("is:%d\n", emp1.id);
    }

【问题讨论】:

  • 标准警告:不要像 malloc 和朋友返回的那样投射 void *。并且sizeof char 永远不会是1 - 这是由标准定义的。
  • 您 100% 确定服务器和客户端使用相同的结构布局结束字节序?在不同系统之间发送结构化数据的二进制图像通常是一个坏主意。改为使用正确的字段序列化。
  • @olaf 那我该怎么办?我想将记录从客户端发送到服务器
  • 请完整阅读cmets!我想您可以使用您选择的搜索引擎。
  • 服务器:'if(recvfrom(sd, recvBuf, recvBufSize, 0, (struct sockaddr *) &clientAddr, &len) 服务器套接字是'connfd'。即使您确实收到了任何东西,您也假设在“recvBuf”中有一个以空字符结尾的字符串——这当然不能保证。在处理 SOCK_STREAM 时,您必须正确处理由 recv() 或 recvfrom() 返回的结果。您应该了解 strlen() 和 printf("%s..") 的作用。

标签: c linux sockets struct client-server


【解决方案1】:

您正在发送一个包含一个整数和一个字符 指针 的结构。该指针指向接收系统上的一个完全随机的位置。 您必须发送内容name 指向。

您可以单独发送结构的每个成员。对于可变长度的成员,您必须先发送大小并在接收端分配它。

正如 John Bollinger 所说:您的一个结构被打包,另一个没有。这可能会导致结构的布局和大小出现其他问题,并且可能是不必要的。

【讨论】:

  • 另外,一个来源使用#pragma pack 而另一个没有。这可能会导致两个程序对布局甚至结构的大小有不同的想法。没有特别的理由来打包结构;最好放弃。
  • @robin.koch 需要做什么
  • @user3145350:查看我的编辑。
  • 不要担心客户端发送的内容过多——服务器无论如何都不会收到任何东西:(
  • 既然你这么说......可能不是实际代码,或者关于实际问题/错误的信息太少。
【解决方案2】:

添加此答案以回答 OP 的特定问题(它可能看起来有点偏离原始问题)。

简单流式传输的示例。这很简单,因为在真实的流式传输场景中,您需要对象 ID 才能实例化和加载真实的类。但是如果你已经知道你正在发送或接收什么类,他们就不需要这种复杂性。如果要发送多个类实例,则需要更复杂的流式传输机制。正如微软在 MFC 中所做的那样,在 OWL 中的 Borland,.NET 也有适当的机制,...

namespace OMCIPoco{

typedef std::vector<unsigned char> ucharvector;

SystemData::stream& operator <<(SystemData::stream& stream,const ucharvector& data);
SystemData::stream& operator >>(SystemData::stream& stream,ucharvector& data);

}

cpp 文件:

SystemData::stream& operator <<(SystemData::stream& stream,const ucharvector& data)
{
    stream << (unsigned long)data.size();
    for (ucharvector::const_iterator it=data.begin();it<data.end();++it)
        stream << *it;
    return stream;
}
SystemData::stream& operator >>(SystemData::stream& stream,ucharvector& data)
{
    unsigned long count;
    stream >> count;
    data.reserve(count);
    for (unsigned int i=0;i<count;++i){
        unsigned char c;
        stream >> c;
        data.push_back(c);
    }
    return stream;
}

注意> 是如何平衡的。 流是一个接口,可以抽象出您要流式传输到的媒体,它可以是内存、磁盘或网络流。我也可以在这里使用流概念解决小端序问题,因为流知道如何(反)序列化 short、long 等,而且它也知道如何缓冲。

您也可以使用扁平结构,完全避免上述复杂性

class data{
public:
   char name[20];
};

现在使用 sizeof(data) 将是正确的,因为您将发送整个数据结构。我在这里使用了类,但结构的工作方式相同。缺点是如果名称仅包含 10 个字符,您仍将发送 20 个。

【讨论】:

    猜你喜欢
    • 2020-08-16
    • 1970-01-01
    • 2014-09-07
    • 2018-06-27
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 2022-01-12
    相关资源
    最近更新 更多