简体   繁体   English

c ++ socket关闭第一次连接尝试

[英]c++ socket closing the first connection attempt

I'm trying to make a server sample in c++ using <sys/socket.h> and Qt Creator gui builder but two weird behaviors are going on at socket layer of the program. 我正在尝试使用<sys/socket.h>和Qt Creator gui builder在c ++中创建服务器示例,但是在程序的套接字层上发生了两种奇怪的行为。 First of, I run the server but at the first attempt I make to connect to it using telnet is imediately closed 首先,我运行服务器,但在第一次尝试使用telnet连接到它时,它会立即关闭

Trying 127.0.0.1... 试试127.0.0.1 ......
Connected to 127.0.0.1. 连接到127.0.0.1。
Escape character is '^]'. 逃脱角色是'^]'。
Connection closed by foreign host. 外部主机关闭连接。

When I attempt connection for the second time, it works and the terminal waits for my input. 当我第二次尝试连接时,它工作,终端等待我的输入。 The second thing is when I close the connection. 第二件事是我关闭连接。 If I rerun right after, in a matter of minutes, the program halts on bind exiting and returning: 如果我在几分钟内重新运行,程序会在bind退出和返回时停止:

ERROR on binding: Address already in use 绑定时出错:地址已在使用中

So I suppose maybe a connection is being held after I break it using function call onCortarConexao() or just stopping the debugger. 所以我想在使用函数调用onCortarConexao()或者只是停止调试器之后可能会断开连接。 Anyway, what am I missing? 无论如何,我错过了什么?

My code: 我的代码:

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

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

On MainWindow.cpp: 在MainWindow.cpp上:

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

Socket class: 套接字类:

#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

Socket implementation: 套接字实现:

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

}

The complete code is at: https://github.com/FabioNevesRezende/BasicCppServer 完整的代码位于: https//github.com/FabioNevesRezende/BasicCppServer

Edit 1: 编辑1:

So, this is the list of packets of the communication between telnet and my Qt Server application it can be graphicaly seen in WireShark (.pcapng file). 因此, 是telnet和我的Qt服务器应用程序之间通信的数据包列表,它可以在WireShark (.pcapng文件)中图形化。 It contains 11 frames. 它包含11帧。 The 6 first ones are from the first telnet, when it is imediately closed. 6个第一个来自第一个telnet,当它立即关闭时。 As it seems on frame 4 and 5 where the application sends [FIN, ACK] and the server responds to it by closing the connection. 正如第4帧和第5帧所示,应用程序发送[FIN, ACK] ,服务器通过关闭连接来响应它。 The frames 7,8,9 are the second attempt to connect and frames 10 and 11 is when I send the abc to the server. 帧7,8,9是第二次连接尝试,帧10和11是我将abc发送到服务器时。 As in the print screen: 如在打印屏幕中:

命令序列

The problem is I don't know why the application is sending this FIN and where in the code it is. 问题是我不知道为什么应用程序发送此FIN以及它在代码中的位置。

Use SO_REUSEADDR with setsockopt : SO_REUSEADDRsetsockopt一起使用:

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

This allows the port to be reused by other sockets and gets around the address already in use issue you're facing. 这允许端口被其他套接字重用,并绕过您正在address already in useaddress already in use

The previous answers have indicate that how to handle the read correctly and how to use SO_RESUEADDR. 以前的答案表明如何正确处理读取以及如何使用SO_RESUEADDR。 I want to point out why your program can just receive one message. 我想指出为什么你的程序只能收到一条消息。 because your run function doesn't have a loop, so it can be only performed once, then the thread exits. 因为你的run函数没有循环,所以它只能执行一次,然后线程退出。 after accept a client's request, then the connection is establish, then you should enter a loop to wait the client's input, and write them back once the read function returns. 接受客户端的请求后,建立连接,然后你应该进入一个循环来等待客户端的输入,并在读取函数返回后写回。

Here's the first serious problem I found: 这是我发现的第一个严重问题:

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

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

There's no handling for read returning zero. read返回零没有处理。 The %s format specifier is only for strings. %s格式说明符仅适用于字符串。 You can't use it for arbitrary, unchecked data. 您无法将其用于任意未经检查的数据。

On unix operating systems, system calls can sometimes fail with an errorno set to EINTR. 在unix操作系统上,系统调用有时会失败,并且errorno设置为EINTR。 This means that a signal was delivered to the process which interrupted the system call and you should retry it. 这意味着信号已传送到中断系统调用的进程,您应该重试它。 Try something like this: 尝试这样的事情:

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

The same should be done for the call to write. 写入调用也应该这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM