通过结构中的字符通过c

时间:2018-09-26 10:56:54

标签: c sockets tcp char

我正在尝试在服务器和客户端之间发送/接收消息。我的服务器上当前有一个存储char值的结构。我正在尝试将此值传递给我的客户。请参阅以下内容:

tileInfo->tiles[user_cords_x][user_cords_y].identifier = '+'; // Char i want to pass
write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier);

/* Writes a message to a client socket. */
void write_client_msg(int cli_sockfd, char * msg)
{
    int n = write(cli_sockfd, msg, strlen(msg));
    if (n < 0)
        error("ERROR writing msg to client socket");

}

在我的客户端上,我收到以下信息:

char *msg;
char identity = read(sockfd, msg, 1);
printf("This is the value: %d \n", identity);

当前我得到的输出是This is the value: 1。我是套接字新手,不完全理解传递字符。有人可以解释一下,告诉我如何将“ +”传递给我的客户端吗?

3 个答案:

答案 0 :(得分:1)

您的代码有几个错误。

在服务器端,此代码:

write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier);

很明显identifier是单个char,否则代码将无法编译。在这种情况下,在strlen()内使用write_client_msg()是错误的,因为在传递指向单个msg的指针时char将没有空终止符。如果不仅仅因为访问无效内存而导致崩溃,您最终将把垃圾传输给另一方。

然后,在客户端,您要将未初始化的msg指针传递给read()。而且,您正在显示read()的返回值,这是实际接收到的字节数。这就是为什么您的显示器上显示1的原因,因为您要求接收1个字节。

要正确发送和接收identifier,您将需要以下类似内容:

void write_client_msg(int sockfd, char *msg, size_t msg_len)
{
    int n = write(sockfd, msg, msg_len);
    if (n < 0)
        error("ERROR writing msg to client socket");
}

...

write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier, 1);

char identity;
int n = read(sockfd, &identity, 1);
if (n < 0)
    error("ERROR reading identity from client socket");
else if (n == 0)
    error("DISCONNECTED while reading identity from client socket");
else
    printf("This is the value: %c \n", identity);

话虽这么说,一种更好的解决方案是使write_client_msg()在发送msg_len之前先发送msg。特别是由于write_client_msg()不知道它正在发送哪种数据。然后,客户端可以读取msg_len来知道要为msg读取多少字节,然后根据需要处理msg

此外,write()read()返回的字节数少于请求的字节数,因此您需要循环调用它们以确保您实际发送/接收所有内容。

例如:

int write_all(int sockfd, void *data, size_t data_len)
{
    char *d = (char*) data;
    while (data_len > 0)
    {
        int n = write(sockfd, d, data_len);
        if (n < 0)
            return n;
        d += n;
        data_len -= n;
    }
    return 1;
}

void write_client_msg(int sockfd, char *msg, size_t msg_len)
{
    uint32_t len = htonl(msg_len);
    int n = write_all(sockfd, &len, sizeof(len));
    if (n == 1)
        n = write_all(sockfd, msg, msg_len);
    if (n < 0)
        error("ERROR writing msg to client socket");
}

...

write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier, 1);

int read_all(int sockfd, void *data, size_t data_len)
{
    char *d = (char*) data;
    while (data_len > 0)
    {
        int n = read(sockfd, d, data_len);
        if (n <= 0)
            return n;
        d += n;
        data_len -= n;
    }
    return 1;
}

char *read_server_msg(int sockfd)
{
    uint32_t len;
    int n = read_all(sockfd, &len, sizeof(len));
    if (n <= 0)
        return NULL;
    len = ntohl(len);
    char *msg = malloc(len+1);
    if (!msg)
        return NULL;
    n = read_all(sockfd, msg, len);
    if (n <= 0) {
        free(msg);
        return NULL;
    }
    msg[len] = '\0';
    return msg;
}

...

char *msg = read_server_msg(sockfd);
if (!msg)
    error("ERROR reading msg from client socket");
else {
    printf("This is the value: %s \n", msg);
    free(msg);
}

答案 1 :(得分:-1)

正确的解决方案(基于您的代码)将是:

private void updateList() {
        FirebaseRecyclerOptions<User> userOptions = new FirebaseRecyclerOptions.Builder<User>()
                .setQuery(counterRef,User.class)
                .build();

        adapter = new FirebaseRecyclerAdapter<User, ListOnlineViewHolder>(userOptions) {
            @Override
            protected void onBindViewHolder(@NonNull ListOnlineViewHolder viewHolder, int position, @NonNull final User model) {
                if(!model.getEmail().equals(FirebaseAuth.getInstance().getCurrentUser().getEmail()))
                    viewHolder.txtEmail.setText(model.getEmail()+"(me)");
                else
                    viewHolder.txtEmail.setText(model.getEmail());

                //we need implement item click f recycler view

                viewHolder.itemClickListener=(ItemClickListener)(view, position);{
                //if model is current user, not set click event
                if (!model.getEmail().equals(FirebaseAuth.getInstance().getCurrentUser().getEmail())) {
                    Intent map = new Intent(ListOnline.this, MapTracking.class);
                    map.putExtra("email", model.getEmail());
                    map.putExtra("lat", mLastLocation.getLatitude());
                    map.putExtra("lng", mLastLocation.getLongitude());
                    startActivity(map);
                }

答案 2 :(得分:-3)

已解决:

char *msg;
msg = (char*) malloc (1);
read(sockfd, msg, 1);
printf("Sent received: %s \n", msg);