多线程并发,处理长连接或者耗时网络操作,提高并发服务效率,相对于select,epoll模型来说,理解简单,适用于单服务器简单负载。
Linux多线程并发网络编程代码
/* sokcet_thread.c
编译:
gcc -g -o socket_thread socket_thread.c -lpthread
*/
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <signal.h>
-
#include <pthread.h>
-
#define PORT 9999
-
#define MAXSOCKFD 10
-
void *process_client( void *pdata );
-
void handle_sigcld(int signo);
-
struct targs{
-
int sockfd; // socket id
-
pthread_t tid; // 线程id
-
char *ip;
-
int timeout;
-
};
-
int main( int argc, char *argv[] )
-
{
-
int sockfd, connfd;
-
struct sockaddr_in servaddr, cliaddr;
-
socklen_t cliaddr_len;
-
fd_set readfds;
-
char buffer[256];
-
char msg[] = "Welcome to server!";
-
if ( (sockfd=socket(AF_INET,SOCK_STREAM,0))<0 )
-
{
-
perror("socket");
-
return 1;
-
}
-
bzero(&servaddr, sizeof(servaddr));
-
servaddr.sin_family = AF_INET;
-
servaddr.sin_port = htons(PORT);
-
servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
-
int reuse = 1;
-
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
-
&reuse, sizeof(int)) < 0){
-
perror("setsockopt error");
-
return 1;
-
}
-
if ( bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr) ) != 0 )
-
{
-
perror("connetc");
-
return 1;
-
}
-
if ( listen(sockfd,5) != 0 )
-
{
-
perror("listen");
-
return 1;
-
}
-
//允许中断退出
-
#if 0
-
signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */
-
#else
-
signal(SIGCLD, handle_sigcld); /* 处理中断信息*/
-
#endif
-
while (1)
-
{
-
cliaddr_len = sizeof( struct sockaddr);
-
connfd = accept(sockfd, (struct sockaddr*)&cliaddr,&cliaddr_len );
-
if (connfd < 0 ){
-
perror("accept");
-
continue;
-
}
-
/*新的连接,启动一个线程处理:
-
其实这里可以将线程ID保存起来,以便主进程对其进行管理,比如进程退出
-
时,对所以线程进行销毁,这里暂时不用了,简单点吧。
-
1,如果要实现可以将pthreadArgs,压入一个全局链表,对每一个线程进行管理,
-
2,如果需要传入一些全局配置信息到子线程中,可以通过pthreadArgs结构体参数传入
-
如果有些参数需要读写,还需要做线程间互斥。*/
-
struct targs *pthreadArgs = (struct targs*)malloc(sizeof(struct targs) );
-
pthreadArgs->sockfd = connfd;
-
pthread_t pid = 0;
-
int pthread = pthread_create(&pid, NULL, process_client, (void *)pthreadArgs);
-
if ( pthread != 0 ){
-
perror("create thread");
-
}else{
-
pthreadArgs->tid = pid;
-
//加入全局链表,方便管理
-
}
-
}
-
return 0;
-
}
-
/* 处理子线程 */
-
void *process_client( void *pdata )
-
{
-
char *preaddata = NULL;
-
struct targs *pta= (struct targs*)pdata;
-
if ( pdata == NULL )
-
goto EXIT_POINT;
-
int connfd = pta->sockfd;
-
char buffer[1024];
-
printf("thread process socket:%d\n", connfd);
-
/*先收4个字节长度*/
-
bzero(buffer,sizeof(buffer));
-
if ( read(connfd,buffer,4)<=0 ){
-
goto EXIT_POINT;
-
}
-
/*再收内容*/
-
int len = atoi(buffer);
-
printf("packet length:%04d\n", len );
-
if ( len <= 0 ) goto EXIT_POINT;
-
preaddata = (char *)calloc(len+1, 1);
-
if ( !preaddata ) goto EXIT_POINT;
-
if ( read(connfd,preaddata ,len)<=0 ) {
-
printf("connetc closed.\r\n");
-
goto EXIT_POINT;
-
}
-
else
-
{
-
printf("recv from client:[%s]\r\n",preaddata );
-
}
-
#if 1 // 以下这段代码可以替换成自己的实际业务代码,比如查询数据库等。
-
/*将小写转换成大写*/
-
int i = 0;
-
while ( i<len ){
-
char c = *(preaddata+i);
-
if ( c>='a' && c<='z' )
-
*(preaddata+i) -= ('a'-'A');
-
i++;
-
}
-
//模拟2秒等待时间
-
sleep(2);
-
#endif
-
write(connfd, preaddata, len );
-
printf("return client:[%s]\r\n",preaddata);
-
-
EXIT_POINT:
-
if ( pta ){
-
close(pta->sockfd);
-
free(pta);
-
}
-
if (preaddata) free(preaddata);
-
-
/*释放thread,不然内存资源一直会占用不释放,造成泄漏。避免方法
-
可以在主线程pthread_join 回收,也可以通过detach分离释放*/
pthread_detach(pthread_self());
-
return NULL;
-
}
-
void handle_sigcld(int signo)
-
{
-
int pid,status;
-
pid = waitpid( -1, &status, 0);//-1表示等待任何子进程
-
//printf("child process %d exit with %d\n",pid,status);
-
}
阅读(835) | 评论(0) | 转发(0) |