2016-08-14 9 views
5

<sys/socket.h>とQt Creator GUIビルダーを使用してC++でサーバーサンプルを作成しようとしていますが、プログラムのソケットレイヤーで2つの奇妙な動作が行われています。まずの、私は、サーバーを実行するが、私はtelnetを使用して、それに接続するために作る最初の試みでimediately ... 127.0.0.1をしようと127.0.0.1に接続
最初の接続試行を終了するC++ソケット

を閉じています。
エスケープ文字は '^]'です。
外部ホストによって接続が切断されました。

2回目の接続を試みると、それは動作し、端末は自分の入力を待ちます。もう一つは、接続を閉じるときです。私は右の後に再実行する場合は、ほんの数分で、プログラムが終了し、帰国bindに一時的に停止させます。

ERROR結合に:すでに使用

で住所をだから私は多分、接続が開催されていると仮定関数呼び出しonCortarConexao()を使用してブレークした後、またはデバッガを停止するだけです。とにかく、私は何が欠けていますか?

マイコード:MainWindow.cppオン

#include "mainwindow.h" 
#include <QApplication> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    MainWindow w; 
    w.show(); 
    return a.exec(); 
} 

void MainWindow::on_pushButton_clicked() 
{ 
    socket1 = new MSocket(); 
    socket1->start(); 
} 
void MainWindow::on_pushButton_3_clicked() 
{ 
    socket1->onCortarConexao(); 
} 

ソケットクラス:

#ifndef MSOCKET_H 
#define MSOCKET_H 
#include <QString> 
#include <QObject> 
#include <QThread> 
#include <QList> 
#include <string.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <unistd.h> 
#define SERVER_BUFFER 4096 
#define PORTRUN 15000 


class MSocket : public QThread 
{ 
public: 
    MSocket(); 
    void error(char *msg); 
    void onCortarConexao(); 

private: 
    int sockfd; 
    int newsockfd; 
    int portno; 
    int clilen; 
    int n; 
    char buffer[SERVER_BUFFER]; 
    struct sockaddr_in serv_addr, cli_addr; 
    u_short port; 
    void run(); 
}; 

#endif // MSOCKET_H 

ソケットの実装:

void MSocket::run() 
{ 
sockfd = socket(AF_INET, SOCK_STREAM, 0); 

if (sockfd < 0){ 
    error("ERROR opening socket"); 
    exit(-1); 
} 
bzero((char *) &serv_addr, sizeof(serv_addr)); 

portno = PORTRUN; 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_port = htons(portno); 
serv_addr.sin_addr.s_addr = INADDR_ANY; 

fprintf(stdout,"Iniciando servidor.."); 
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){ 

    error("ERROR on binding"); 
    exit(-1); 
} 
listen(sockfd,5); 

newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) sizeof(cli_addr)); 
if (newsockfd < 0){ 
    error("ERROR on accept"); 
    exit(-1); 
} 

bzero(buffer,SERVER_BUFFER); 
n = read(newsockfd,buffer,SERVER_BUFFER-1); 
if (n < 0) 
    error("ERROR reading from socket"); 

printf("Here is the message: %s",buffer); 

n = write(newsockfd,"I got your message",18); 
if (n < 0) 
    error("ERROR writing to socket"); 




} 

void MSocket::onCortarConexao(){ 
    printf("Encerrando socket"); 
    close(newsockfd); 
    close(sockfd); 

} 
だから

thisは、それがgraphicaly WireSharkの(で見ることができ、telnetや私のQt Serverアプリケーション間の通信のパケットのリストです:https://github.com/FabioNevesRezende/BasicCppServer

編集1:

完全なコードはです.pcapngファイル)。それは11フレームを含んでいます。最初の6つは、即時に閉じられたときの最初のtelnetからのものです。フレーム4と5でアプリケーションが[FIN, ACK]を送信し、サーバーが接続を閉じることによって応答したようです。フレーム7,8,9は接続する2番目の試みであり、フレーム10と11はサーバにabcを送信するときです。印刷画面のように:

sequence of commands

問題は、アプリケーションがそれがコード内でこのFIN、どこを送信している理由を私は知らないです。 setsockopt

+0

githubプロジェクト用に提供したリンクが壊れています。それがなければ、2回目の試行で何を意味するのかは、クライアント側でやり直すか、サーバーを再起動するかだけではわかりません。明確にできますか? – lasaro

+0

申し訳ありませんが、もう一度やります。 – Fabiotk

答えて

4

使用SO_REUSEADDR

optval = 1; 
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); 

これは、ポートが他のソケットで再利用することができ、あなたが直面している問題を回避address already in use取得します。

n = read(newsockfd,buffer,SERVER_BUFFER-1); 
if (n < 0) 
    error("ERROR reading from socket"); 

printf("Here is the message: %s",buffer); 

ゼロを返すreadための取り扱いはありません:

+0

ありがとう、それは2番目の問題を解決しました。 – Fabiotk

+1

なぜ将来の訪問者に良いQ + Aになるのか説明したいかもしれません。 –

3

は、ここで私が最初に見つかった深刻な問題です。 %sの書式指定子は、文字列にのみ適用されます。チェックされていない任意のデータには使用できません。

3

UNIXオペレーティングシステムでは、EINTRにerrornoを設定するとシステムコールが失敗することがあります。これは、システムコールを中断したプロセスにシグナルが送られたことを意味し、再試行する必要があります。

while ((n = read(newsockfd,buffer,SERVER_BUFFER-1) < 0) { 
if (errno != EINTR) 
break; 
} 
if (n < 0) 
    error("ERROR reading from socket"); 

書き込みのために同じことを行う必要があります。

5

これまでの回答は、読み取りを正しく処理する方法と、SO_RESUEADDRを使用する方法を示しています。 あなたのプログラムがただ1つのメッセージを受け取れる理由を指摘したいと思います。あなたの実行関数はループを持たないので、スレッドは一度しか実行できず、スレッドは終了します。クライアントの要求を受け入れてから接続が確立されたら、クライアントの入力を待つためにループを開始し、読み込み関数が返ったらそれらを書き戻す必要があります。

+0

良い点。私はそれを完全に逃した。 –

関連する問題