- 论坛徽章:
- 1
|
#include<stdio.h>
#include <stdlib.h>
#include<strings.h>
#include <string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#define PORT 4502
#define BACKLOG 1
#define MAXDATASIZE 4000
#define ONLINE 8000 /*定义一个最大5000人在线的情况*/
#define PTHREAD_THREADS_MAX 50 /*允许一个进程创建这个数量的线程*/
struct ARG
{
int connfd[ONLINE][6]; //用户信息列表 数字型
char *connfds[ONLINE][20]; //用户信息列表 字符串型
int currently,pthread_id[PTHREAD_THREADS_MAX];
struct sockaddr_in client;
int pth;//下一个线程
};
////////////////////////////////////////
void *func(void *arg );
int simulate_accept(void *arg,int pt);
int acceptfz(void *arg,int client_fd,int e);
///////////////////////////////////
int main()
{
pthread_t tid;
pthread_attr_t attr;
int listenfd,i, connectfd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t addrlen;
char buf[MAXDATASIZE];
struct ARG *arg, in;
arg = ∈
printf("初始化数据\n" ;
for (i=0;i<ONLINE;i++)
{
//初始化在线人数
arg->connfd[0]=0;//连接句柄
arg->connfd[1]=0;//联盟ID
arg->connfd[2]=0;//门派ID
arg->connfd[3]=0;//是否允许登陆0为不允许
arg->connfd[4]=0;//使用那个线程
arg->connfd[5]=0;//是否已经加入select的句柄集
arg->connfds[0]=(char*)"";//昵称
arg->connfds[1]=(char*)"";//玩家用户名
}
arg->pth=100;
printf("启动线程\n" ;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);//把线程脱离出去
pthread_attr_setstacksize(&attr,512);//线程堆贱大小
for(i=0;i< THREAD_THREADS_MAX;i++)
{
//创建50个应用线程
if(pthread_create(&tid,&attr, func, (void *)arg))
{
perror("error pthread_create2" ;
}
printf("启动处理线程%d\n",tid);
arg->pthread_id=tid;//取得线程ID
}
printf("建立socket\n" ;
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket() error." ;
//exit(1);
}
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("bind() error." ;
//exit(1);
}
if(listen(listenfd, BACKLOG) == -1)
{
perror("listen() error." ;
//exit(1);
}
printf("主程序进入守护状态\n" ;
addrlen = sizeof(client);
while(1)
{
if((arg->currently= accept(listenfd, (struct sockaddr *)&client, &addrlen )) == -1)
{
perror("accept() error." ;
//exit(1);
}
acceptfz(arg,arg->currently,1);//像socket注册句柄
}
return 0;
}
void *func(void *arg)
{
//便利属于这个线程的100个用户
//pthread_detach(pthread_self());//上面已经把这个线程分离出来啦
struct ARG *args;
args = (struct ARG *)arg;
int retval,i,j,pt=pthread_self();//取得线程ID
int in=0;
char *tmp[20];
char*bufs = (char *) malloc ( sizeof(int) *MAXDATASIZE);
fd_set rfds;
struct timeval tv;
int oks=0,maxfd=-1;
maxfd = 0;
while(1)
{
i=simulate_accept(args,pt);//返回用户下标
printf("句柄分析 %i-------用户序列号:%i\n",args->connfd[0],i);
//提取出属于自己线程的句柄,并且句柄不能为0
//是否加入集合中
if(args->connfd[5]==0)
{
//把集合清空
FD_ZERO(&rfds);
// 把当前连接句柄new_fd加入到集合中
FD_SET(args->connfd[0], &rfds);
args->connfd[5]=1;
printf("已将句柄 %i 加入到集合中----%i\n",args->connfd[0],i);
}
if (args->connfd[0] > maxfd)
{
maxfd = args->connfd[0];
}
// 设置最大等待时间
tv.tv_sec = 0;
tv.tv_usec =100;
//printf("最大句柄----%i\n",maxfd);
// 开始等待
retval = select(maxfd+1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror("select error." ;
continue;
} else if (retval == 0) {
//printf("没有任何消息到来,继续等待……%i\n",i);
continue;
} else {
printf("有一个操作信号\n");
if (FD_ISSET(args->connfd[0], &rfds))
{
memset(bufs, 0, MAXDATASIZE);
memset(tmp, 0, 20);
if (read(args->connfd[0], bufs, MAXDATASIZE)< 0)
{
perror("read error");
acceptfz(args,args->connfd[0],0);
close(args->connfd[0]);
//exit(0);
continue;
}
printf("读取客户端信息: %s\n",bufs);
}
}
}
}
//将accept加入到用户列表中或注销
int acceptfz(void *arg,int client_fd,int e)
{
struct ARG *info;
info = (struct ARG *)arg;
int j;
if(e==1)
{
for(j=0;j<ONLINE;j++)
{
//找一个空的句柄存储仓
if(info->connfd[j][0]==0)
{
//将句柄交给存储仓
info->connfd[j][0]=client_fd;//句柄注册
//为句柄分配线程号
if(info->pth==100 || info->pth==PTHREAD_THREADS_MAX)
{
info->pth=1;
info->connfd[j][4]=info->pthread_id[0];//初始化第一个
}else{
info->connfd[j][4]=info->pthread_id[info->pth];
printf("新线程号:%i--------pth:%i\n",info->pthread_id[info->pth],info->pth);
info->pth++;
}
printf("将连接句柄交给%s:%i,线程号:%i\n","connfd",info->connfd[j][0],info->connfd[j][4]);
return j;
}
}
}else{
for(j=0;j<ONLINE;j++)
{
if(info->connfd[j][0]==client_fd)
{
printf("用户:%i连接被销毁\n", info->connfd[j][0]);
info->connfd[j][0]=0;
info->connfd[j][1]=0;
info->connfd[j][2]=0;
info->connfd[j][3]=0;
info->connfd[j][4]=0;
info->connfd[j][4]=0;
info->connfds[j][0]="";
info->connfds[j][1]="";
pthread_exit((char*)pthread_self());//销毁线程释放内存
break;
}
}
}
return 0;
}
int simulate_accept(void *arg,int pt)
{
struct ARG *args;
args = (struct ARG *)arg;
int i,j,oks=0;
//int j = (int ) malloc (sizeof(int)* 5);
for(i=0;i>-1;i++)
{
if(i==ONLINE){i=0;}
for (j=0;j<ONLINE;j++)
{
if(args->connfd[j][4]==pt && args->connfd[j][0]!=0 && args->connfd[j][5]==0)
{
printf("已经检查到一个新句柄 %i----用户序列号:%i----是否在集合中%i\n",args->connfd[j][0],j,args->connfd[j][5]);
return j;
}
}
if(oks==0)
{//句柄列表中是否有有效的连接
//printf("线程处于等待状态%d\n",pt);
sleep(1);
continue;
}
}
}
代码我是提取出来的,帮我看看逻辑是否有问题,我是新学C的,忘高手帮忙看下为什么select检查不到我前台发送过来的数据(就是read给没被执行到郁闷,连接正常)。
这个是我自己写的,我的思路是想让一个线程守候端口,如果有客户端连接则忘一个数组里把这个句柄加入到数组中,
然后其他50个线程就处理这个数组中的数据,acceptfz函数在守候线程里就开始分配句柄属于那个线程的
[ 本帖最后由 jd808 于 2009-8-6 16:18 编辑 ] |
|