PPC的C/C++和人工智能学习笔记
每一篇学习笔记,都只是为了更好地掌握和理解

linux开发(9)_网络编程(4)测试用客户端

使用最基本的socket同步模式,建立一个测试用的客户端。为接下来学习select、poll、epoll模型做准备。

 

客户端的功能要求:

  • 短连接测试(端口4444):客户端connect服务器,发送1K数据,接收1K数据,关闭连接;
  • 长连接测试(端口5555):客户端connect服务器,发送40K数据,接收40K数据,重复100次以后,关闭连接。
  • 短连接总连接次数为100万次,客户端开启10个线程来实现;
  • 长连接总连接次数为1万次,客户端开启10个线程来实现;
  • 显示每秒完成的短连接次数、长连接次数、失败次数;

 

主线程:

  • 开启10个线程,开始短连接的测试
  • 循环检测长连接发送个数,并保持最多只开启10个线程来进行长连接测试。意思就是:长连接线程每次创建只完成一个连接的收发,收发次数完成就关闭线程。

 

 

//easy tcp client

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>

void* print_thread(void* arg); //打印线程函数
void* short_thread(void* arg); //短连接线程
void* long_thread(void* arg); //长连接线程
int init_client_socket(); //创建client_socket
int connect_server(int fd,int port); //连接服务器,失败返回-1
void set_block_timeout(int fd,int ms); //设置阻塞模式下的超时,单位是毫秒
int data_send(int fd,void* buf,int len); //客户端发送函数
int data_recv(int fd,void* buf,int len); //客户端接收函数

#define S_THREAD_COUNT 10 //短连接线程数
#define L_THREAD_COUNT 10 //长连接线程数
#define L_SEND_RECV_COUNT 100 //长连接收发次数

int g_short_count = 1000000; //短连接总数
int g_long_count = 10000; //长连接总数
volatile int g_short_now = 0; //当前短连接完成数量
volatile int g_long_now = 0; //当前长连接完成数
volatile int g_error = 0; //当前错误的连接数

sem_t sem_long; //长连接线程数 的 信号量

int main(){
 pthread_t thread_print,thread_id;
 int err,i;
 err = pthread_create(&thread_print,NULL,print_thread,NULL);
 if(err!=0){
 perror("pthread_create print_thread error!");
 exit(EXIT_FAILURE);
 }
 //开启 短连接测试线程
 for(i=0;i<S_THREAD_COUNT;++i){
 pthread_create(&thread_id,NULL,short_thread,NULL);
 }
 //开启 长连接测试
 sem_init(&sem_long,0,L_THREAD_COUNT); //初始化信号量,起始有10个
 while(g_long_now<g_long_count){
 ++g_long_now;
 sem_wait(&sem_long);
 pthread_create(&thread_id,NULL,long_thread,NULL);
 }
 
 pthread_join(thread_print,NULL); //在这里等待打印线程结束
 sem_destroy(&sem_long);
 return 0;
}

void* print_thread(void* arg){
 int i = 0;
 printf("sec\t\ts_all\t\tl_all\t\ttotal_err\n");
 while(1){ //死循环,不退出
 sleep(1);
 printf("%d\t\t%d\t\t%d\t\t%d\n",
 ++i,g_short_now-S_THREAD_COUNT,g_long_now,g_error);
 }
}

void* short_thread(void* arg){
 pthread_detach(pthread_self());
 char buf[1024];
 int client_sock = -1;
 while(__sync_fetch_and_add(&g_short_now,1)<g_short_count){
 usleep(10);
 client_sock = init_client_socket();
 if(connect_server(client_sock,4444)<0){
 close(client_sock);
 continue;
 }
 //设置同步模式下的 超时 3000毫秒
 set_block_timeout(client_sock, 3000);
 //发送、接收
 if(data_send(client_sock,buf,sizeof(buf))==0)
 data_recv(client_sock,buf,sizeof(buf));
 close(client_sock);
 }
}

void* long_thread(void* arg){
 pthread_detach(pthread_self());
 char buf[1024*40];
 int client_sock = -1;
 int count = 0;
 client_sock = init_client_socket();
 if(connect_server(client_sock,5555)<0){
 close(client_sock);
 sem_post(&sem_long);
 return;
 }
 for(count=0;count<L_SEND_RECV_COUNT;++count){ //连续收发100次
 usleep(10);
 if(data_send(client_sock,buf,sizeof(buf))==0)
 data_recv(client_sock,buf,sizeof(buf));
 }
 close(client_sock); 
 sem_post(&sem_long);
}

int init_client_socket(){
 int fd = socket(AF_INET,SOCK_STREAM,0);
 if(fd<0){
 perror("create socket error!");
 exit(EXIT_FAILURE);
 }
 return fd;
}

int connect_server(int fd,int port){
 int ret = -1;
 struct sockaddr_in server_addr;
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(port);
 server_addr.sin_addr.s_addr= inet_addr("192.168.31.233");
 bzero(&server_addr.sin_zero,8);
 ret = connect(fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
 if(ret<0){
 //perror("connect error!");
 __sync_fetch_and_add(&g_error,1);
 }
 return ret;
}

void set_block_timeout(int fd,int ms){
 struct timeval timeout;
 timeout.tv_sec = ms / 1000; //秒
 timeout.tv_usec = ( ms % 1000 ) * 1000; //微妙
 if(setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout)) <0 ){
 perror("setsockopt SO_RCVTIMEO error!");
 exit(EXIT_FAILURE);
 }
 if(setsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout)) <0 ){
 perror("setsockopt SO_SNDTIMEO error!");
 exit(EXIT_FAILURE);
 }
}

int data_send(int fd,void* buf,int len){
 int index = 0; //起始发送的位置
 int nbytes = 0;
 int ret = -1;
 while(1){
 nbytes = send(fd, buf+index, len-index, 0);
 //阻塞模式下,不管这些: EAGAIN == errno || EWOULDBLOCK == errno || EINTR == errno,出错就认为错误了
 if(nbytes <=0){
 perror("send error!");
 ret = -1;
 break;
 }
 index += nbytes;
 if(index == len){ //全部发送完毕
 ret = 0;
 break;
 }
 }
 if(ret == -1){
 __sync_fetch_and_add(&g_error,1);
 }
 return ret;
}

int data_recv(int fd,void* buf,int len){
 int index = 0; //起始接收的位置
 int nbytes = 0;
 int ret = -1;
 while(1){
 nbytes = recv(fd, buf+index, len-index, 0);
 if(nbytes <=0){
 perror("recv error!");
 ret = -1;
 break;
 }
 index += nbytes;
 if(index == len){
 ret = 0;
 break;
 }
 }
 if(ret == -1){
 __sync_fetch_and_add(&g_error,1);
 }
 return ret;
}

 

(2017-11-22 www.vsppc.com)

学习笔记未经允许不得转载:PPC的C/C++和人工智能学习笔记 » linux开发(9)_网络编程(4)测试用客户端

分享到:更多 ()

评论 抢沙发

评论前必须登录!