字符串连接维护目标长度

时间:2017-06-03 14:39:24

标签: c string sockets server concatenation

我有一个基本的服务器 - 客户端程序,我用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;

}

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

1 个答案:

答案 0 :(得分:0)

由于这一行,它只打印第一个用户(Mark):

int people_n = len_data / (LENGTH+1);

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

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