tl:dr(長すぎる、読んでいない)の投稿を決定する前に、少なくともいくつかを読んでみてください。その質問は多くの小さな断片に分解されているからです。そのうちのいくつかはおそらく答えて私を助けることができます。
できる限り助けてください。これらのタイプの問題はインターネット上で非常に一般的であり、あなたは私と私の後のはるかに多くの人々を助けてくれると思います。
私は現在、HTTPサービスとプロトコル自体を調査しており、それが自分にとって役立つかどうかを知ることができます。
いくつかの基本的な質問と、議論する必要のあるコードがあります。
まず、コミュニケーションはどのように始まるのか知りたいのですが?クライアントがリソースを要求するメッセージを送信することを発見しました(これは正しいですか?)。では、どうなりますか?私は(サーバーとして)何で返信する必要がありますか?
すべての応答の後に、キャリッジリターンとラインフィードを追加する必要がありますか?どこかに、2つ必要であると書かれています(\ r \ n \ r \ n)。
非同期書き込みを確立するにはどうすればよいですか?(この質問が理解できることを願っています)私の主な目標は、クライアントとサーバー間の接続を実現し、サーバーからクライアントへの継続的なデータストリームを実現することです。クライアントは、受信するすべてのメッセージに返信する必要がありますか?
私はこれらのことの専門家ではないので、質問を明確にしたいと思います(それでも、私はそれに非常に興味があります)。
そして、私の問題のプログラミング部分について。
私は、C ++(サーバー側)のQtで簡単なプログラムを作成し、Objective C(iOS)で簡単なクライアントを作成することができました。クライアントが接続し、リクエストヘッダーを読み取ることができます。これは次のようなものです。
Data available, incoming: "GET / HTTP/1.1
Host: localhost:9990
Connection: close
User-Agent: CFStream%20test/1.0 CFNetwork/609 Darwin/12.2.0
このヘッダーに手動で返信する必要がありますか?もしそうなら、何ですか?
クライアント側のコードは次のようになります(疑似ではないことはわかっていますが、かなり自明だと思います)。
- (void)setupStream
{
NSURL *url = [NSURL URLWithString:@"http://localhost:9990"];
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (CFURLRef)url, kCFHTTPVersion1_1);
stream = CFReadStreamCreateForHTTPRequest(NULL, message);
CFRelease(message);
if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue))
{
NSLog(@"Some error.");
}
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings);
CFRelease(proxySettings);
if (!CFReadStreamOpen(stream))
{
CFRelease(stream);
NSLog(@"Error opening stream.");
}
CFStreamClientContext context = {0, self, NULL, NULL, NULL};
CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred, readStreamCallback, &context);
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
NSLog(@"Done");
}
これがセットアップストリーム方式です。stream
変数は、型のクラス変数ですCFReadStreamRef
。
コールバックは次のようになります。
static void readStreamCallback(CFReadStreamRef aStream, CFStreamEventType event, void *client)
{
ViewController *controller = (ViewController*)client;
[controller handleEvent:event forStream:aStream];
}
そして、このようなハンドルイベント:
- (void)handleEvent:(CFStreamEventType)event forStream:(CFReadStreamRef)aStream
{
if (aStream != stream)
{
return;
}
NSLog(@"Handle event callback");
switch (event)
{
case kCFStreamEventHasBytesAvailable:
NSLog(@"Work log");
UInt8 bytes[11];
CFIndex length;
length = CFReadStreamRead(stream, bytes, 11); //I know 11 bytes is hard coded, its in testing stage now. Feel free to suggest me how to do it better.
if (length == -1)
{
NSLog(@"Error, data length = -1");
return;
}
NSLog(@"Len: %li, data: %s", length, bytes);
break;
default:
NSLog(@"Other event");
break;
}
}
そして、それは事実上、言及する価値のあるすべてのクライアントコードです。Qtサーバーの部分(重要な部分のみを投稿します)は次のように実行されます:(これはサブクラス化されたQTcpServerクラスです)。最初にstartServer();
呼び出されます:
bool Server::startServer()
{
if (!this->listen(QHostAddress::Any, 9990))
return false;
return true;
}
着信接続がある場合incomingConnection
、パラメータとしてソケット記述子を使用して起動されます。
void Server::incomingConnection(int handle)
{
qDebug("New client connected");
ServerClient *client = new ServerClient(handle, this); //The constructor takes in the socket descriptor needed to set up the socket and the parent (this)
client->setVectorLocation(clients.count()); //This is a int from a Qvector in which i append the clients, its not important for understanding right now.
connect(client, SIGNAL(clientDisconnected(int)), this, SLOT(clientDisconnected(int)), Qt::QueuedConnection); //When the client socket emits a disconnected signal the ServerClient class emits a client disconnected signal which the server uses to delete that client from the vector (thats why I use "setVectorLocation(int)") - not important right now
clients.push_back(client); //And then I append the client to the QVector - not important right now
}
ClientServer
クラスコンストラクターは、新しいソケットを作成し、必要なメソッドを接続するだけです。
ServerClient::ServerClient(int handle, QObject *parent) :
QObject(parent)
{
socket = new QTcpSocket(this); //Socket is a class variable
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
socket->setSocketDescriptor(handle);
}
Ready readは、着信データを書き込むだけです(後でユーザーが増えることはないと思います)。
void ServerClient::readyRead()
{
qDebug() << "Data available, incoming: " << socket->readAll();
}
そして最後に書き込みデータ:
void ServerClient::writeData(QByteArray *data)
{
data->append("\r\n\r\n"); //I have read this must be appended to all outgoing data from a HTTP server
socket->write(*data);
socket->flush();
qDebug() << "Written data to client: " << *data;
}
ただし、このコードは常に機能するとは限りません。「メッセージ」のようなメッセージを書くと、クライアントはすべてのデータとそこにあるべきではないいくつかのものを受け取ることがあります(新しい行と奇妙な記号-NSLog
これを引き起こす可能性がありますか?)。"Hellow"
時々私がクライアントを送るとき、"Hel"
他のいくつかのファンキーなものだけを手に入れます。
問題は何ですか?何にもっと注意を払うべきですか?私を助けるものは何でも大いに感謝されるでしょう。そして、数百ページの本を含むいくつかのリンクを貼り付けないでください。これは私に物事を説明するだけで解決できると確信しています。
どうもありがとう!
1月