2016-08-14 10 views
5

बंद करने मैं सी में एक सर्वर नमूना ++ <sys/socket.h> और क्यूटी निर्माता GUI बिल्डर लेकिन दो अजीब व्यवहार का उपयोग कर बनाने के लिए कोशिश कर रहा हूँ कार्यक्रम के सॉकेट लेयर पर पर जा रहे हैं। सबसे पहले, मैं सर्वर चलाते लेकिन पहले ही प्रयास में मैं तुरंतC++ सॉकेट पहले कनेक्शन का प्रयास

कोशिश कर रहा 127.0.0.1 ...
127.0.0.1 से कनेक्ट किया गया बंद कर दिया है यह telnet का उपयोग कर से कनेक्ट है।
एस्केप कैरेक्टर '^]' है।
कनेक्शन विदेशी होस्ट द्वारा बंद कर दिया गया।

जब मैं दूसरी बार कनेक्शन का प्रयास करता हूं, तो यह काम करता है और टर्मिनल मेरे इनपुट के लिए इंतजार कर रहा है। दूसरी बात यह है कि जब मैं कनेक्शन बंद करता हूं।

त्रुटि बंधन पर:: पता पहले से ही उपयोग में

तो मैं शायद एक कनेक्शन किया जा रहा है लगता है अगर मैं सही होने के बाद फिर से चलाएं, मिनट की बात में, कार्यक्रम bind पर बाहर निकलने और लौटने रुकती है फ़ंक्शन कॉल onCortarConexao() या केवल डीबगर को रोककर इसे तोड़ने के बाद। वैसे भी, मुझे क्या याद आ रही है?

मेरे कोड:

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

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

MainWindow.cpp पर:

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); 

} 

पूरा कोड है पर: https://github.com/FabioNevesRezende/BasicCppServer

संपादित करें 1:

तो, this टेलनेट और मेरे क्यूटी सर्वर आवेदन के बीच संचार के पैकेट की सूची यह graphicaly WireShark में देखा जा सकता है (.pcapng फ़ाइल)। इसमें 11 फ्रेम हैं। 6 सबसे पहले पहले टेलनेट से होते हैं, जब यह तुरंत बंद हो जाता है। जैसा कि यह फ्रेम 4 और 5 पर लगता है जहां एप्लिकेशन [FIN, ACK] भेजता है और सर्वर कनेक्शन बंद करके इसका जवाब देता है। कनेक्ट करने के लिए दूसरा प्रयास 7,8,9 है और फ्रेम 10 और 11 है जब मैं सर्वर पर abc भेजता हूं। प्रिंट स्क्रीन में के रूप में:

sequence of commands

समस्या मैं क्यों आवेदन कोड यह है में इस FIN और जहां भेज रहा है पता नहीं है है। setsockopt साथ

+0

आपके जीथब प्रोजेक्ट के लिए आपके द्वारा प्रदान किया गया लिंक टूटा हुआ है। इसके बिना मैं यह नहीं बता सकता कि दूसरे प्रयास से आपका क्या मतलब है क्लाइंट पक्ष पर फिर कोशिश कर रहा है या सर्वर को पुनरारंभ करना भी है। क्या आप स्पष्टीकरण दे सकते हैं? – 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

धन्यवाद, यह दूसरी समस्या हल हो गया। – Fabiotk

+1

आप यह बताना चाहते हैं कि यह भविष्य के आगंतुकों के लिए एक अच्छा क्यू + ए बनाने के लिए क्यों काम करता है। –

3

यहाँ पहले गंभीर समस्या मैंने पाया है। %s प्रारूप विनिर्देश केवल तारों के लिए है। आप इसे मनमाने ढंग से, अनचेक डेटा के लिए उपयोग नहीं कर सकते हैं।

3

यूनिक्स ऑपरेटिंग सिस्टम पर, सिस्टम कॉल कभी कभी एक errorno EINTR करने के लिए सेट के साथ विफल कर सकते हैं। इसका मतलब यह है कि प्रक्रिया में एक सिग्नल वितरित किया गया था जो सिस्टम कॉल में बाधा डालता था और आपको इसे पुनः प्रयास करना चाहिए। इस तरह कुछ कोशिश करें:

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

कॉल लिखने के लिए भी ऐसा ही किया जाना चाहिए।

5

पिछले जवाब है संकेत मिलता है कि कैसे संभाल करने के लिए पढ़ने के लिए सही ढंग से और कैसे SO_RESUEADDR उपयोग करने के लिए। मैं यह इंगित करना चाहता हूं कि आपका प्रोग्राम सिर्फ एक संदेश क्यों प्राप्त कर सकता है। क्योंकि आपके रन फ़ंक्शन में लूप नहीं होता है, इसलिए इसे केवल एक बार किया जा सकता है, फिर थ्रेड निकलता है। ग्राहक के अनुरोध को स्वीकार करने के बाद, कनेक्शन स्थापित हो गया है, तो आपको क्लाइंट के इनपुट की प्रतीक्षा करने के लिए एक लूप दर्ज करना चाहिए, और पढ़े जाने के बाद उन्हें वापस लिखना चाहिए।

+0

अच्छा बिंदु। मैं पूरी तरह से याद किया। –

संबंधित मुद्दे