【问题标题】:Using printf with threads and socket programming将 printf 与线程和套接字编程一起使用
【发布时间】:2016-11-24 03:10:28
【问题描述】:

我正在使用套接字编程制作一个服务器,它与客户对他说的话相呼应。但是当我打印出消息(由客户端发送)和它的长度时,消息和它的长度不匹配。我正在使用 printf 进行打印。

我基本上想要的是在客户端键入“退出”时关闭连接。但是 strcmp("exit",clientmessage) 不起作用。

服务器代码:

//for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

void *function(void *s)
{
    int s1;
    int n;
    char rmsg[500];
    s1 = *(int *)s;
    while((n = read(s1,rmsg,499)) > 0) {
        rmsg[n] = '\0';
        printf("%s %d\n",rmsg,strlen(rmsg));
        bzero(rmsg,499);
    }
    pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
    struct sockaddr_in server,client;
    int s1,len;
    int s2;
    int n;
    int i = 0;
    int port;
    pthread_t t1;
    char message[500];
    port = atoi(argv[1]);
    bzero((char *)&server,sizeof(server));
    server.sin_port = htons(port);
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_family = AF_INET;
    s1 = socket(AF_INET,SOCK_STREAM,0);
    if(s1 == -1) {
        perror("socket not created\n");
        exit(1);
    }
    if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
        perror("socket not binded\n");
        exit(1);
    }
    if(listen(s1,5) == -1) {
        perror("unable to listen");
        exit(1);
    }
    len = sizeof(struct sockaddr_in);
    s2 = accept(s1,(struct sockaddr *)&client,&len);
    pthread_create(&t1,NULL,function,(void *)&s2);
    pthread_join(t1,NULL);
    close(s2);
    close(s1);
    return 0;

}

客户端输入:

shivam@shivam-HP-Pavilion-15-Notebook-PC:~$ telnet localhost 8009
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hhh
jhiklmnop

服务器端输出:

shivam@shivam-HP-Pavilion-15-Notebook-PC:~/Study/chat$ ./a.out 8009
hhh
 5
jhiklmnop
 11

修改后的代码:

//for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
void *function(void *s)
{
    int s1;
    int n;
    char rmsg[500];
    s1 = *(int *)s;
    char d[] = {'e','x','i','t','\0'};
    while((n = read(s1,rmsg,499)) > 0) {
        rmsg[n-2] = '\0';
        if(strcmp(d,rmsg) == 0) {
            write(s1,"bye",3);
            close(s1);
        }
        rmsg[n-2] = '\n';
        rmsg[n-1] = '\0';
        write(s1,rmsg,strlen(rmsg));
        bzero(rmsg,499);
    }
    pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
    struct sockaddr_in server,client;
    int s1,len;
    int s2;
    int n;
    int i = 0;
    int port;
    pthread_t t1;
    char message[500];
    port = atoi(argv[1]);
    bzero((char *)&server,sizeof(server));
    server.sin_port = htons(port);
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_family = AF_INET;
    s1 = socket(AF_INET,SOCK_STREAM,0);
    if(s1 == -1) {
        perror("socket not created\n");
        exit(1);
    }
    if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
        perror("socket not binded\n");
        exit(1);
    }
    if(listen(s1,5) == -1) {
        perror("unable to listen");
        exit(1);
    }
    len = sizeof(struct sockaddr_in);
    s2 = accept(s1,(struct sockaddr *)&client,&len);
    pthread_create(&t1,NULL,function,(void *)&s2);
    pthread_join(t1,NULL);
    close(s2);
    close(s1);
    return 0;

}

【问题讨论】:

    标签: c linux sockets pthreads


    【解决方案1】:

    除了用户输入的字符外,当用户按下 Enter 键时,您还会收到回车 (0xd) 和换行 (0xa) 字符。这就是为什么您得到的数字 2 比您预期的要大。

    【讨论】:

      【解决方案2】:

      TCP 是面向流的协议,没有消息边界。所以你不能像你正在做的那样编写依赖于read()的返回值的应用程序逻辑。

      解决方法是使用长度前缀字符串,或通过套接字发送 NUL 终止符。你也可以想出其他机制,但是客户端必须在数据流中告诉服务器消息在哪里结束; TCP 层不会这样做。

      【讨论】:

      • 对此甚至有特殊的 ascii 值(通常用于串行终端,但仍然有用和使用)。我曾经使用过一种可以使用它们的设备。 STX (0x02) 开始文本,我认为它是 0x03 结束文本。因此,OP 也可以使用那些 unused ascii 值。我目前正在使用一个 websocket 服务器,它发送用这些字符分隔的 Json 列表,并且还使用 STX。
      • 当然,我知道。我真的不明白为什么会这样。它是网络上的一项服务,没有任何文档或任何内容,我只是推断了向/从它发送或接收事物的方式,以使用它。但这确实很奇怪。由于您可以在纯 Json 中定义数组,因此不需要任何分隔符或特殊字符。但这就是它的工作方式。
      • @BenVoigt 看看编辑后的代码。删除最后两个字符后它工作正常。这会一直有效吗?
      • @ShivamMitra:不,它不可靠。诸如exit 之类的单个命令可以拆分为多个读取调用(例如,您从第一个调用得到e,然后从第二个调用得到xit\r\n——这真的很糟糕,因为现在索引n-2,您在其中编写NUL字符是负数并且您损坏了另一个对象)或者您可以在单个读取调用中获得多个命令,例如hello\r\nexit\r\n
      猜你喜欢
      • 1970-01-01
      • 2013-01-24
      • 2011-11-10
      • 1970-01-01
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多