我正在进行压力测试:服务器和客户端,服务器接受连接并启动一个线程以继续向套接字写入字节,客户端启动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时,服务器什么也不发送。