【问题标题】:String concatenation maintaining destination length保持目标长度的字符串连接
【发布时间】:2017-11-04 19:37:45
【问题描述】:

我有一个基本的服务器-客户端程序,我正在用 C 语言编写,但我遇到了一个关于字符串和连接的问题。 基本上我有一些字符串(在下面的示例中只有 2 个),我必须将它们放入缓冲区中,其大小由以下因素决定:

  total # of registered people * 33

示例中的两个字符串的长度都远小于缓冲区的长度。我想在连接后获得这样的东西:

            [0]            [32]
people_list=Mark           Amy\0;

Mark(第二个​​插入的)就在缓冲区的开头(people_list),而 Amy 距离 Mark 的开头 32 个字符(我希望我已经说清楚了)。

这是因为客户端代码给了我,我不能修改它。客户端代码获取缓冲区并读取第一个元素,然后跳转 32 个字符并再次读取。 我从客户端的 printf 得到的输出是这样的:

connected to server
Registered people:
 Mark

虽然我想要这样:

connected to server
Registered people:
 Mark
 Amy

通信是通过套接字实现的,我已经检查过了,但如果您希望提出一些更改建议,我将不胜感激。

服务器代码:

#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define LENGTH 32

struct person {
    char name[LENGTH+1];
    struct person *next;
    struct person *prev;

};
struct person *p_head = NULL;

void addPerson(char* name_p){
    struct person *new = (struct person*) malloc(sizeof(struct person));
    strcpy(new->name, name_p);
    new->name[LENGTH]='\0';
    new->next=p_head;
    new->prev=NULL;
    p_head=new;

}

int main(){

    int fd_ser;
    int fd_c;
    int N=100;
    char buf[N];
    int times=0;
    char* path="tmp/sock";

    struct sockaddr_un sa;

    unlink(path);
    sa.sun_family=AF_UNIX;
    strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));

    if((fd_ser=socket(AF_UNIX,SOCK_STREAM,0))<0){   //socket
        perror((const char*) (size_t) errno);
        exit(EXIT_FAILURE);
    }


    if ( bind(fd_ser,(struct sockaddr *)&sa, sizeof(sa))<0){
        perror("bind\n");
    }

    listen(fd_ser,10);  //listen


    struct sockaddr_un addr;
    int addr_size= sizeof(struct sockaddr_un);

    fd_c=0;
    while( (fd_c=accept(fd_ser,(struct sockaddr*) &addr, (socklen_t*)&addr_size))<0){
        printf("waiting for connections...\n");
        sleep(2);
    }


    //initialize list of people
    char* Amy="Amy";
    char* Mark="Mark";

    addPerson(Amy);
    addPerson(Mark);

    //now concat the name strings in a buffer to be sent to the client

    char* people_list;
    unsigned int list_len;
    int value;

    struct person* ptr=(struct person*) malloc(sizeof(struct person));
    ptr=p_head;
    int offset=0;
    int i=0;

    while(ptr!=NULL){
        i++;
        people_list=realloc(people_list,i*LENGTH); //every single name has to be LENGTH characters
        strcpy(&people_list[offset],ptr->name);
        ptr=ptr->next;
        offset=offset+LENGTH;
    }
    people_list[i*LENGTH]='\0';
    list_len=(i*LENGTH)+1;

    value=write(fd_c, &(list_len), sizeof(unsigned int));
    if(value==-1){
        perror("write length");
        return -1;
    }

    int toWrite=list_len;
    char *toRead=people_list;
    while(toWrite>0){
        value=write(fd_c, toRead, toWrite);
        if(value==-1){
            perror("write data");
            return -1;
        }
        toWrite=toWrite-value;
        toRead=toRead+value;
        if(toRead<=people_list + list_len) break;
    }

    close(fd_c);
    close(fd_ser);

    return 0;
}

客户端代码:

#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#define MAX_LENGTH 2048
#define LENGTH 32

int main(){

    int fd_cli;
    char* path="tmp/sock";
    struct sockaddr_un sa;
    sa.sun_family=AF_UNIX;
    strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));

    if( (fd_cli = socket(AF_UNIX, SOCK_STREAM, 0))==-1){
        perror((const char*) (size_t) errno);
        return -1;
    }

    while( (connect(fd_cli,(struct sockaddr*)&sa, sizeof(struct sockaddr_un))) == -1 ) {
        if ( errno == ENOENT ) { sleep(1); }
        else perror("connect:");
        errno=0;
        sleep(1);
    }

    printf("connected to server\n");

    int value;

    unsigned int len_data;

    value=read(fd_cli,&(len_data),sizeof(unsigned int));
    if(value==-1){
        perror("read length");
        return -1;
    }
    char* buffer=malloc(len_data*sizeof(char));

    int toRead=len_data;
    char *toWrite=buffer;
    while(toRead>0){
        value=read(fd_cli, toWrite, toRead);
        if(value==-1){
            perror("read buffer");
            return -1;
        }
        toRead=toRead-value;
        toWrite=toWrite+value;
        if(toWrite<=buffer + len_data) break;
    }


    int people_n = len_data / (LENGTH+1);
    assert(people_n > 0); //proceeds only if there is at least one person registered

    printf("Registered people:\n");

    for(int i=0,p=0;i<people_n; ++i, p+=(LENGTH+1)) {
        printf(" %s\n", &buffer[p]);
    }

    close(fd_cli);

    return 0;

}

我真的希望我已经清楚地解释了这个问题!感谢您的帮助!

【问题讨论】:

  • 你可能要再仔细阅读客户端代码,特别是LENGTH的处理。
  • struct person* ptr=(struct person*) malloc(sizeof(struct person)); ptr=p_head; 你这里内存泄漏了。
  • @EOF 对!我没有考虑过客户端会跳转 LENGTH+1 个字符,而我没有考虑过服务器中的问题,现在我修复了它。我是多么的盲目!谢谢你的提示。
  • @wildplasser 对,谢谢,我会解决的!

标签: c string sockets server concatenation


【解决方案1】:

因为这条线,它只打印第一个用户(马克):

int people_n = len_data / (LENGTH+1);

在此示例中,len_data = 65LENGTH = 32。因此,当您将 1 添加到 LENGTH 时,它将返回 1 (65/33 = 1.96 =&gt; you get 1)。然后它只打印第一个用户。

考虑使用Valgrind。它将帮助您检查内存的使用情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 2022-01-09
    相关资源
    最近更新 更多