我有一个客户端/服务器程序。
客户端循环执行以下操作。
服务器在循环中执行以下操作。
对于某些迭代,这可以正常工作,大约10次迭代后,只能看到在客户端和服务器上读取string2。 为什么这样呢? 另外,在while()循环中的客户端程序中如果在第二次write()之后调用read(),一切正常。
在客户端,从第二次迭代读取()应该返回管道中的整个数据,因为管道没有消息边界。但它只读取服务器中1次write()调用所写的数据。
以下是我的参考代码。
server.c
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main()
{
client_to_server;
char *myfifo = "/tmp/client_to_server_fifo";
int server_to_client;
char *myfifo2 = "/tmp/server_to_client_fifo";
char buf[BUFSIZ];
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
mkfifo(myfifo2, 0666);
/* open, read, and display the message from the FIFO */
client_to_server = open(myfifo, O_RDONLY);
server_to_client = open(myfifo2, O_WRONLY);
printf("Server ON bufsize=%d.\n", BUFSIZ);
while (1)
{
read(client_to_server, buf, BUFSIZ);
if (strcmp("exit",buf)==0)
{
printf("Server OFF.\n");
break;
}
else if (strcmp("",buf)!=0)
{
printf("Received: %s\n", buf);
printf("Sending back...\n");
write(server_to_client,buf,BUFSIZ);
}
/* clean buf from any data */
memset(buf, 0, sizeof(buf));
}
close(client_to_server);
close(server_to_client);
unlink(myfifo);
unlink(myfifo2);
return 0;
}
client.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include<string.h>
int main()
{
int client_to_server;
char *myfifo = "/tmp/client_to_server_fifo";
int server_to_client;
char *myfifo2 = "/tmp/server_to_client_fifo";
char str[BUFSIZ];
/* write str to the FIFO */
client_to_server = open(myfifo, O_WRONLY);
server_to_client = open(myfifo2, O_RDONLY);
char buf1[30] = "str1";
char buf2[30] = "str2";
while(1){
//write first string
write(client_to_server, buf1, sizeof(buf1));
read(server_to_client,str,sizeof(str));
perror("Read:"); // Very crude error check
printf("...received from the server: %s\n",str);
memset(str, '\0', sizeof(str));
//write second string
write(client_to_server, buf2, sizeof(buf2));
}
close(client_to_server);
close(server_to_client);
return 0;
}
以下是输出: 服务器输出: 服务器ON bufsize = 8192。 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str1 发回来...... 收到:str2 发回来...... 收到:str2 发回来...... 收到:str2 发回来...... 收到:str2 发回来...... 收到:str2 发回来...... 收到:str2 发回来...... 收到:str2 发回来...... 收到:str2
以下是客户的输出: ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str1 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2 ...从服务器收到:str2
答案 0 :(得分:0)
简短的回答是客户端和服务器接收&#34; str2 \ 0str1 \ 0&#34;但打印到第一个\ 0,即&#34; str2&#34;。
客户端的长答案不仅仅是字符串&#34; str1&#34;和&#34; str2&#34;但终止NUL:
write(client_to_server, buf1, sizeof(buf1));
sizeof返回字符串的长度加上终止NUL。
现在是服务器端。你读到了BUFSIZ字节。因此,如果客户端足够快,可以发送少量字符串,即&#34; str2 \ 0str1 \ 0&#34;你将一次阅读所有字符串。要解决这个问题,你必须考虑读取的内容,即:
ssize_t ret = read(client_to_server, buf, BUFSIZ);
printf("Received: size %zd\n", ret); // print the size
fwrite(buf, 1, ret, stdout); // print the buffer with NULs
write(server_to_client,buf,ret); // write back just the data you actually received
答案 1 :(得分:0)
您不会检查错误,也不会使用read(2)
的返回值,该值表示读取的字符数。这很奇怪,因为这是不同步的服务器和客户端的来源。我已经以一种不会失败的方式重写了你的代码(尽管我没有检查write(2)
的返回值,它应该在破坏管道时失败 - 杀死服务器或客户端)这是留给你完成的,作为练习。
通过指定printf(3)
格式的字符串长度,关注"%.*s"
调用处理非空终止字符串的方式(这是避免放置最终{{1}的技巧在缓冲区中(如果您正在阅读\0
,则应该检查,而不是sizeof buf
。
sizeof buf - 1
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define F(fmt) __FILE__":%d:%s: " fmt, __LINE__, __func__
/* file scope to share with at_exit() call */
static const char myfifo[] = "/tmp/client_to_server_fifo";
static const char myfifo2[] = "/tmp/server_to_client_fifo";
void rm_fifos(void)
{
printf(F("deleting fifo \"%s\"\n"), myfifo);
unlink(myfifo);
printf(F("deleting fifo2 \"%s\"\n"), myfifo2);
unlink(myfifo2);
}
int main()
{
int client_to_server;
int server_to_client;
int res;
char buf[BUFSIZ];
/* create the FIFO (named pipe) */
printf(F("creating fifo \"%s\"\n"), myfifo);
res = mkfifo(myfifo, 0666 | O_EXCL); /* O_EXCL guarantees that no second instance is created while this is running */
if (res < 0) {
fprintf(stderr,
F("%s: %s(errno=%d)\n"),
myfifo, strerror(errno), errno);
exit(EXIT_FAILURE);
}
printf(F("creating fifo \"%s\"\n"), myfifo);
res = mkfifo(myfifo2, 0666 | O_EXCL);
if (res < 0) {
fprintf(stderr,
F("%s: %s(errno=%d)\n"),
myfifo2, strerror(errno), errno);
unlink(myfifo); /* we successfuly created it */
exit(EXIT_FAILURE);
}
atexit(rm_fifos);
/* open, read, and display the message from the FIFO */
client_to_server = open(myfifo, O_RDONLY);
if (client_to_server < 0) {
fprintf(stderr,
F("%s: open: %s(errno=%d)\n"),
myfifo, strerror(errno), errno);
exit(EXIT_FAILURE);
}
server_to_client = open(myfifo2, O_WRONLY);
if (server_to_client < 0) {
fprintf(stderr,
F("%s: open: %s(errno=%d)\n"),
myfifo2, strerror(errno), errno);
exit(EXIT_FAILURE);
}
printf(F("Server ON bufsize=%d.\n"), BUFSIZ);
while (1) {
ssize_t n = read(client_to_server, buf, BUFSIZ);
if (n < 0) {
fprintf(stderr,
F("%s: read: %s(errno = %d)\n"),
myfifo, strerror(errno), errno);
exit(EXIT_FAILURE);
}
if (n == 0) break; /* EOF on input */
printf("Received: [%.*s]\n", n, buf);
printf("Sending back...\n");
write(server_to_client, buf, n); /* very important to write just the n read chars, and not more */
/* no need to clean buf from any data */
}
close(client_to_server);
close(server_to_client);
/* no need to unlink, as this was prepared in the atexit() library call */
return 0;
}