windows/cygwin でやってみました。
クライアント側は送信後に同一ソケットから受信するならソケットをクローズ出来ません(※)ので、サーバの recv が 0 で戻ることはありません。
ですので、 recv が 0 を返すまで読み込んでから送信するというコードは期待した動作にはならないでしょう。
※ shutdown システムコールのことをすっかり忘れていました。 shutdown を使えば送信側だけを閉じることが出来ますので、クライアント側が送信後にそうすることが決まっていれば、サーバ側は『切断まで受信する』形で出来ます。
以下では '\0' を区切りとしています。
tcptest.c
c
1#include <stdio.h>
2#include <unistd.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8
9void tcpclient(int port, char *message) {
10 int sock = socket(AF_INET, SOCK_STREAM, 0);
11 if(sock < 0) {
12 perror("socket");
13 return;
14 }
15
16 struct sockaddr_in addr;
17 addr.sin_family = AF_INET;
18 addr.sin_port = htons(port);
19 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
20
21 connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
22
23 if(send(sock, message, strlen(message)+1, 0) < 0) { //'\0'まで送る
24 perror("send");
25 close(sock);
26 return;
27 }
28
29 char buf[256];
30 int len;
31 for(int i=0; (len=recv(sock, &buf[i], sizeof(buf)-i,0)) > 0; i+=len); //切断まで
32
33 if(len < 0) {
34 perror("recv");
35 close(sock);
36 return;
37 }
38
39 printf(buf);
40
41 close(sock);
42}
43
44void reply(int sock, char *message) {
45 if(send(sock, message, strlen(message)+1, 0) < 0) {
46 perror("send");
47 }
48}
49
50struct {
51 char *request;
52 char *response;
53} DATA[] = {
54 { "年齢", "19" },
55 { "性別", "men" },
56 { NULL, NULL } //EOD
57};
58
59void echo(int sock) {
60 char buf[256];
61
62 for(int i=0, len; (len=recv(sock, &buf[i], sizeof(buf)-i,0)) > 0; i+=len) {
63 for(int j=0; j<len; j++) {
64 if(buf[i+j] == '\0') { //'\0'まで受け取っていたら
65 printf(buf);
66 for(int i=0; DATA[i].request != NULL; i++) {
67 if(strcmp(buf, DATA[i].request) == 0) {
68 reply(sock, DATA[i].response);
69 return;
70 }
71 }
72 reply(sock, "(error)");
73 return;
74 }
75 }
76 }
77 perror("recv");
78}
79
80void tcpserver(int port) {
81 int ss = socket(AF_INET, SOCK_STREAM, 0);
82 if(ss < 0) {
83 perror("socket");
84 return;
85 }
86
87 struct sockaddr_in addr;
88 addr.sin_family = AF_INET;
89 addr.sin_port = htons(port);
90 addr.sin_addr.s_addr = INADDR_ANY;
91 if(bind(ss, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
92 perror("bind");
93 close(ss);
94 return;
95 }
96
97 if(listen(ss, 10) < 0) {
98 perror("listen");
99 close(ss);
100 return;
101 }
102
103 struct sockaddr_in caddr;
104 socklen_t csize = sizeof(caddr);
105
106// while(1) {
107 int sock = accept(ss, (struct sockaddr *)&caddr, &csize);
108 if(sock < 0) {
109 perror("accept");
110 close(ss);
111 return;
112 }
113
114 echo(sock);
115 close(sock);
116// }
117
118 close(ss);
119}
120
121#define PORT 12345
122
123int main(int argc, char **argv) {
124 if(argc >= 2) tcpclient(PORT, argv[1]);
125 else tcpserver(PORT);
126
127 return 0;
128}
サーバ
plain
1F:\teratail_c\Debug>tcptest.exe
2年齢
3F:\teratail_c\Debug>tcptest.exe
4性別
5F:\teratail_c\Debug>tcptest.exe
6あいう
クライアント
plain
1F:\teratail_c\Debug>tcptest.exe 年齢
219
3F:\teratail_c\Debug>tcptest.exe 性別
4men
5F:\teratail_c\Debug>tcptest.exe あいう
6(error)