首页 > 解决方案 > 无法在套接字编程中将 int 从服务器发送到客户端

问题描述

我是 Socket 编程的新手,并试图制作一个服务器-客户端程序,其中客户端首先发送文件名,然后服务器打开该文件并计算文件的大小并将大小发送回客户端。

虽然在服务器端,我可以计算文件的大小,但无法将其发送回客户端。

我得到的filesize是0。

以下是代码:

服务器

#include<iostream>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
using namespace std;

int  filesize(char* fname){
    FILE *f=fopen(fname,"r");
    fseek(f,0,SEEK_END);
    int len=ftell(f);
    fclose(f);
    //cout<<"\nlength= "<<len;
    return len;


}

int main(){
    int sockid=socket(AF_INET,SOCK_STREAM,0);
    if(sockid<0){
        cout<<"Failed Creating socket\n";
        return 0;
    }

    int client_socket;
    struct sockaddr_in server, client;
    int client_size=sizeof(client);
    server.sin_family=AF_INET;
    server.sin_port=htons(8791);
    server.sin_addr.s_addr=htonl(INADDR_ANY);

    if(bind(sockid,(struct sockaddr*)&server,sizeof(server))<0){
        cout<<"Failed binding\n";
        return 0;
    }
    cout<<"binded";

    if(listen(sockid,4)<0){
        cout<<"Failed listening\n";
        return 0;
    }
    cout<<"Listening....\n";
    if((client_socket=accept(sockid,(struct sockaddr*)&client, (socklen_t*)&(client_size)))<0){
        cout<<"Failed accepting\n";
        return 0;
    }
    cout<<"Connecting\n";



    char fname[]={0};

    int x=recv(client_socket,fname,1024,0);

    cout<<fname<<endl;

    //char fname[]={"a.txt"};
    fname[x]='\0';

    int fsize=filesize(fname);
    cout<<"FILE SIZE : "<<fsize<<endl;

    //int fsize=58;

    if(send(client_socket,&fsize,sizeof(int),0)<0){
        cout<<"failed sending SIZE\n";
        return 0;
    }

    return 0;
}

客户端代码:

#include<iostream>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
using namespace std;


int main(){

    int sockid=socket(AF_INET,SOCK_STREAM,0);
    if(sockid<0){cout<<"Failed creating socket\n";return 0;}


    struct sockaddr_in client;
    client.sin_family=AF_INET;
    client.sin_port=htons(8797);
    client.sin_addr.s_addr=htonl(INADDR_ANY);

    if(connect(sockid,(struct sockaddr*)&client,sizeof(client))<0){
        cout<<"Failed connecting\n";
        return 0;
    }
    cout<<"Connected\n";

    cout<<"Enter File name : ";
    char fname[1024];
    cin>>fname;
    if(send(sockid,fname,strlen(fname),0)<0){
        cout<<"Failed receiving\n";
    }


    int  fsize;

    if(recv(sockid,&fsize,sizeof(int),0)<0){
        cout<<"failed receiving file_size\n";
        return 0;
    }

    cout<<"\nFILE-SIZE : "<<fsize;  

    return 0;
}

标签: c++socketsfile-handling

解决方案


TCP 是一个字节流。send()并且recv()可以返回比请求更少的字节,因此您需要在循环中调用它们以确保您发送/接收您期望的所有字节。

此外,您需要以您知道一条消息在哪里结束以及下一条消息从哪里开始的方式来构建您的消息。

此外,整数应始终使用固定宽度整数类型传输,多字节整数应始终按网络字节顺序(大端)传输,以实现跨平台边界的一致性。

尝试这样的事情:

服务器

#include <iostream>
#include <string>
#include <limits>
#include <cstdint>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

bool filesize(const std::string &fname, std::uint32_t &fsize)
{
    FILE *f = fopen(fname.c_str(), "rb");
    if (!f)
    {
        std::cout << "Failed opening file\n";
        return false;
    }

    if (fseek(f, 0, SEEK_END) != 0)
    {
        std::cout << "Failed seeking file\n";
        fclose(f);
        return false;
    }

    long len = ftell(f);
    fclose(f);

    if (len == -1L)
    {
        std::cout << "Failed getting file size\n";
        return false;
    }

    if (sizeof(long) > sizeof(std::uint32_t))
    {
        if (len > std::numeric_limits<std::uint32_t>::max())
        {
            std::cout << "File size exceeds uint32_t max\n";
            return false;
        }
    }

    fsize = static_cast<std::uint32_t>(len);
    return true;
}

int readAll(int sock, void *buffer, int buflen)
{
    char *ptr = static_cast<char*>(buffer);
    int x;

    while (buflen > 0)
    {
        x = recv(sock, ptr, buflen, 0);
        if (x <= 0)
        {
            if (x == 0)
                std::cout << "Client disconnected\n";
            else
                std::cout << "Failed reading socket, error " << errno << "\n";
            return x;
        }

        ptr += x;
        buflen -= x;
    }

    return 1;
}

int readUInt32(int sock, std::uint32_t &value)
{
    int x = readAll(sock, &value, sizeof(value));
    if (x <= 0) return x;
    value = ntohl(value);
    return 1;
}

int readString(int sock, std::string &s)
{
    s.clear();

    // approach 1: null-terminated string

    char buffer[1024];
    int x, offset = 0;

    do
    {
        x = readAll(sock, &buffer[offset], 1);
        if (x <= 0)
            return x;

        if (buffer[offset] == '\0')
            break;

        if (++offset == sizeof(buffer))
        {
            s.append(buffer, offset);
            offset = 0;
        }
    }
    while (true);

    if (offset > 0)
        s.append(buffer, offset);

    return 1;

    // approach 2: length-prefixed string

    std::uint32_t size;
    int x = readUInt32(sock, size);
    if ((x > 0) && (size > 0))
    {
        s.resize(size);
        x = readAll(sock, &s[0], size);
    }

    if (x <= 0)
        return x;

    return 1;
}

bool sendAll(int sock, const void *buffer, int buflen)
{
    const char *ptr = static_cast<const char*>(buffer);
    int x;

    while (buflen > 0)
    {
        x = send(sock, ptr, buflen, 0);
        if (x < 0)
        {
            std::cout << "Failed sending socket, error " << errno << "\n";
            return false;
        }

        ptr += x;
        buflen -= x;
    }

    return true;
}

bool sendBool(int sock, bool value)
(
    std::uint8_t temp = value;
    return sendAll(sock, &temp, sizeof(temp));
}

bool sendUInt32(int sock, std::uint32_t value)
{
    value = htonl(value);
    return sendAll(sock, &value, sizeof(value));
}

int main()
{
    int sockid = socket(AF_INET, SOCK_STREAM, 0);
    if (sockid < 0)
    {
        std::cout << "Failed creating socket, error " << errno << "\n";
        return 0;
    }

    int client_socket;
    struct sockaddr_in server, client;
    socklen_t client_size;

    server.sin_family = AF_INET;
    server.sin_port = htons(8791);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    socklen_t client_size;

    if (bind(sockid, (struct sockaddr*)&server, sizeof(server)) < 0)
    {
        std::cout << "Failed binding socket, error " << errno << "\n";
        close(sockid);
        return 0;
    }
    std::cout << "Binded";

    if (listen(sockid, 4) < 0)
    {
        std::cout << "Failed listening socket, error " << errno << "\n";
        close(sockid);
        return 0;
    }
    std::cout << "Listening....\n";

    client_size = sizeof(client);
    if ((client_socket = accept(sockid, (struct sockaddr*)&client, &client_size)) < 0)
    {
        std::cout << "Failed accepting client socket\n";
        close(sockid);
        return 0;
    }
    std::cout << "Client connected\n";

    std::string fname;
    if (readString(client_socket, fname) <= 0)
    {
        close(client_socket);
        close(sockid);
        return 0;
    }

    std::cout << fname << "\n";

    std::uint32_t fsize;
    bool success = filesize(fname, fsize);

    if (!sendBool(client_socket, success))
    {
        std::cout << "Failed sending file size reply\n";
    }
    else if (success)
    {
        std::cout << "FILE SIZE : " << fsize << std::endl;      

        if (!sendUInt32(client_socket, fsize))
            std::cout << "Failed sending file size\n";
    }

    close(client_socket);
    close(sockid);

    return 0;
}

客户

#include <iostream>
#include <string>
#include <cstdint>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

int readAll(int sock, void *buffer, int buflen)
{
    char *ptr = static_cast<char*>(buffer);
    int x;

    while (buflen > 0)
    {
        x = recv(sock, ptr, buflen, 0);
        if (x <= 0)
        {
            if (x == 0)
                std::cout << "Server disconnected\n";
            else
                std::cout << "Failed reading socket, error " << errno << "\n";
            return x;
        }

        ptr += x;
        buflen -= x;
    }

    return 1;
}

int readBool(int sock, bool &value)
{
    std::uint8_t temp;
    int x = readAll(sock, &temp, sizeof(temp));
    if (x <= 0) return x;
    value = (temp != 0);
    return 1;
}

int readUInt32(int sock, std::uint32_t &value)
{
    int x = readAll(sock, &value, sizeof(value));
    if (x <= 0) return x;
    value = ntohl(value);
    return 1;
}

bool sendAll(int sock, const void *buffer, int buflen)
{
    const char *ptr = static_cast<const char*>(buffer);
    int x;

    while (buflen > 0)
    {
        x = send(sock, ptr, buflen, 0);
        if (x < 0)
        {
            std::cout << "Failed sending socket, error " << errno << "\n";
            return false;
        }

        ptr += x;
        buflen -= x;
    }

    return true;
}

bool sendString(int sock, const std::string &s)
{
    // approach 1: null-terminated string

    return sendAll(sock, s.c_str(), s.size()+1);

    // approach 2: length-prefixed string

    std::uint32_t size = s.size();
    return sendUInt32(sock, size) && sendAll(sock, s.c_str(), size);
}

int main()
{
    int sockid = socket(AF_INET, SOCK_STREAM, 0);
    if (sockid < 0)
    {
        std::cout << "Failed creating socket, error " << errno << "\n";
        return 0;
    }

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(8797);
    server.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(sockid, (struct sockaddr*)&server, sizeof(server)) < 0)
    {
        std::cout << "Failed connecting socket, error " << errno << "\n";
        close(sockid);
        return 0;
    }
    std::cout << "Connected\n";

    std::cout << "Enter File name : ";
    std::string fname;
    std::getline(std::cin, fname);

    if (!sendString(sockid, fname))
    {
        std::cout << "Failed sending file name\n";
        close(sockid);
        return 0;
    }

    bool success;
    if (readBool(sockid, success) <= 0)
    {
        std::cout << "Failed receiving file size reply\n";
        close(sockid);
        return 0;
    }

    if (success)
    {
        std::uint32_t fsize;
        if (readUInt32(sockid, fsize) <= 0)
        {
            std::cout << "Failed receiving file size\n";
            close(sockid);
            return 0;
        }

        std::cout << "FILE-SIZE : " << fsize << "\n";   
    }
    else
        std::cout << "FILE-SIZE error\n";

    close(sockid);
    return 0;
}

推荐阅读