关闭时TCP连接丢失

时间:2018-08-16 10:46:37

标签: unix tcp high-load

我正在进行压力测试:服务器和客户端,服务器接受连接并启动一个线程以继续向套接字写入字节,客户端启动N个线程以连接服务器并继续接收字节,直到该线程读取5Mb,它将关闭套接字并中断while循环,因此服务器线程的write(send)将返回-1,并将errno设置为EPIPE或ECONNRESET。

问题是,当我在客户端启动1000个线程时,通常会丢失一些TCP连接。为什么?以及如何处理呢?

服务器代码:

#include <pthread.h>
#include <iostream>
using namespace std;
struct cap {
    int connfd;
};
void * thread_fun(void*arg){
    pthread_detach(pthread_self());
    int connfd;
    cap * p=(cap* )arg;
    connfd=p->connfd;
    char buffer[2000];
    while(1){
        memset(buffer,'a',sizeof(buffer));
        int nwrite=write(connfd,buffer,sizeof(buffer));
        if(nwrite<=0){
            if(errno==EPIPE ){
                close(connfd);
                break;
            }else if(errno ==ECONNRESET){
                close(connfd);
                break;
//                    err_sys((WHERE).c_str());
            }
            else{
                err_sys((WHERE).c_str());
            }
        }
    }
    int a=1;
}

int main(){
    signal(SIGPIPE, SIG_IGN);
    struct sockaddr_in servaddr;
    int listenfd;
    listenfd=socket(AF_INET,SOCK_STREAM,0);
    int enable;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
        perror("setsockopt(SO_REUSEADDR) failed");
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    int listening_port=9999;
    servaddr.sin_port = htons(listening_port);
    bind(listenfd, (sockaddr *) &servaddr, sizeof(servaddr));
    listen(listenfd, LISTENQ);
    printf("server running at port %d\n", listening_port);
    pthread_t tid;
    int connfd1;
    while(1){
        connfd1 = accept(listenfd, NULL, NULL);
        struct cap *p_cap = new struct cap;
        p_cap->connfd = connfd1;
        pthread_create(&tid, NULL, thread_fun, (void *) p_cap);    }
    return 0;
}

客户代码:

extern "C" {
#include "wrap.h"
}
#include <iostream>
#include <memory>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#include "wrap.h"
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <sys/time.h>
#include <set>

using namespace std;
pthread_mutex_t m1=PTHREAD_MUTEX_INITIALIZER;
long long all=0;
pthread_mutex_t mc=PTHREAD_MUTEX_INITIALIZER;
int con=0;
struct sockaddr_in servaddr;

int complete=0;
int complete_failed=0;

int n;

void * fun(void *){
    pthread_detach(pthread_self());
    sleep(1);
    pthread_t self_id=pthread_self();
    char thread_name[20];
    const int getname_rv = pthread_getname_np(self_id, thread_name, 20);
    if (getname_rv)
    {
        errno = getname_rv;
        perror("Could not get pthread name");
    }
//    cout<<"thread_name: "<<thread_name<<endl;
    int connfd;
    connfd=socket(AF_INET,SOCK_STREAM,0);
    timeval t1;
    gettimeofday(&t1,NULL);
    int state=connect(connfd,(sockaddr*) &servaddr,sizeof(servaddr));
    if(state<0){
        pthread_mutex_lock(&mc);
        complete_failed++;
        pthread_mutex_unlock(&mc);
        return NULL;
//      err_sys((WHERE).c_str());
    }else{
        pthread_mutex_lock(&mc);
        con++;
        pthread_mutex_unlock(&mc);
    }

    char buff[BUFFERSIZE];
    int n_read=0;
    while(1) {
        int temp=read(connfd,buff,sizeof(buff));
//      cout<<thread_name<<" read "<<temp<<endl;
        if(temp<0){
            err_sys((WHERE).c_str());
        }
        if(temp==0){
            pthread_mutex_lock(&m1);
            complete_failed++;
            cout<<"server close"<<complete_failed<<endl;

            pthread_mutex_unlock(&m1);
            return NULL;

        }
        n_read+=temp;
//      cout<<"tid:"<<thread_name<<" : "<<n_read<<endl;
        if (n_read > 1024 * 1024 * 5){
            pthread_mutex_lock(&m1);
            complete++;
            pthread_mutex_unlock(&m1);
            cout<<"complete"<<complete<<endl;
            close(connfd);
            break;
        }
    }
    timeval t2;
    gettimeofday(&t2,NULL);

    long long delta=1000000*(t2.tv_sec-t1.tv_sec)+(t2.tv_usec-t1.tv_usec);
    pthread_mutex_lock(&m1);
    all+=delta;
//  complete++;
    pthread_mutex_unlock(&m1);

}

int main(int argc, char **argv) {
    socklen_t len;
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(9999);
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    cout<<"cin connections "<<endl;
    cin>>n;
    pthread_t* tids=new pthread_t[n];
    for(int i=0;i<n;i++){
        pthread_t thistid;
        pthread_create(&thistid,NULL,fun,NULL);
        string name=string("thread")+string(to_string(i));
        const int setname_rv = pthread_setname_np(thistid, name.c_str());
    }
    while(1){
        pthread_mutex_lock(&m1);
        cout<<"complete:" <<complete<<endl;
        cout<<"failed"<<complete_failed<<endl;
        cout<<"connected: "<<con<<endl;
        int tem= complete+complete_failed;
        if(tem==n){
            double avg=(double)all/complete;
            cout<<"complete"<<complete<<endl;
            cout<<"failed"<< complete_failed<<endl;
            cout<<"avg"<<avg<<endl;
            pthread_mutex_unlock(&m1);
            break;
        }
        pthread_mutex_unlock(&m1);
        sleep(2);
    }
}

然后我tcpdump了异常和正常连接的日志: 正常连接成功将RST发送到服务器,逻辑符合预期。 异常的连接尝试了几次Handhshake1并成功地建立了3次握手的tcp,但是当连接保持ESTABLISHED时,服务器什么也不发送。

0 个答案:

没有答案