このコードには、問題を引き起こす可能性のあるいくつかの開いた抜け穴があります。本当に私はポイント2に賭けます。
1- connectTCPは実際に機能しますか?実際に動作するTCPソケットを返しましたか。write()
それらをvoidにキャストする代わりに、呼び出すときにエラーをチェックするものを簡単に閉じることができます。
2- LINELENが配列のサイズのように一定である\r\n
場合、ユーザー入力と配列の終わりの間にゴミがあると、配列の終わりに置くことはあまり役に立ちません(おそらく0がある可能性があります)。sizeof(buf)
は最大の有効な値であり、必ずしもユーザーが入力するサイズではありません。
3-double\r\n
は必要ありません。1つの'\n'(unix規則)で十分です。
4-テストにインタラクティブなユーザー入力を使用することは通常は良い考えではありません。コードのデバッグとテストがより困難になります。
5-n
読み取りバッファがいっぱいの場合は、バッファ内の位置に書き込むことに注意してください。バッファの終わりを1つ超えている可能性があります。
5- 1つのコマンドを送信して答えを取得するだけでは不十分な場合は、write()とread()の両方を管理するより複雑なコードを作成する必要があります。別のポスターが示唆しているように、selectは良い考えかもしれません(おそらくスレッドよりも単純です)。送信されたコマンドと受信されたコマンドの交互のブロックをブロックすることもできますが、それはおそらく他の質問のためです。
以下は、答えを得る作業コード(Linuxでgccでテスト済み)です。それほど違いはありませんが、最初のものとは異なり、抜け穴を塞ぐのに役立つことを願っています。
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
enum {
LINELEN = 1024
};
int main(){
char buf[LINELEN];
int n = 0;
unsigned int option_len;
int allow_reuse = 1;
int sck = socket(PF_INET, SOCK_STREAM, 0);
char * ip = "www.google.com";
char * command = "GET http://www.google.com\n";
/* connect to socket */
struct sockaddr_in s;
memset(&s, 0, sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons(80);
s.sin_addr.s_addr = inet_addr(ip);
if (s.sin_addr.s_addr == INADDR_NONE) {
struct hostent *h = gethostbyname(ip);
if (!h) {
printf("DNS resolution failed for %s\n", ip);
exit(0);
}
s.sin_addr.s_addr = *((int*)(*(h->h_addr_list)));
}
connect(sck, (struct sockaddr*)&s, sizeof(s));
/* write command */
printf("Write to socket...\n");
write(sck, command, strlen(command));
/* get answer */
printf("Start reading from socket...\n");
while((n = read(sck, buf, LINELEN-1)) > 0) {
buf[n] = '\0'; /* ensure null-terminated */
fputs( buf, stdout );
}
}