写在前面:这个系列也是停滞了20多天了,从今天开始再次步入正轨,以后每个周末都会陆陆续续的更新,这个系列预计完结的时间还会在大约一个月左右,今天静下心来多整理几篇。QQ:993650814
Linux 网络编程 全解(一)--------网络基础协议
Linux 网络编程 全解(二)--------套接字socket
Linux 网络编程 全解(三)--------TCP三次握手、数据传输、四次挥手、滑动窗口
正文:
一、多进程并发服务器
设计思路:当有新的客户端连接到服务器时,服务器会调用accept函数与客户端建立连接,并创建子进程与连接上来的客户端进行通信。
代码如下:
#include "stdio.h"
#include
#include
#include
#include
#include
#include
#include
#define SER_PORT (9999)
void do_sigchild(int param)
{
printf("%s\n",__FUNCTION__);
while(waitpid(0,NULL,WNOHANG)>0);
}
int main(void)
{
int lfd = -1;
int cfd = -1;
struct sockaddr_in ser_addr;
struct sockaddr_in cli_addr;
pid_t pid = -1;
char buf[1024] = {0x0};
int read_size = 0;
struct sigaction newact;
lfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&ser_addr,0,sizeof(struct sockaddr_in));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(SER_PORT);
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(lfd,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
memset(&newact,0,sizeof(struct sigaction));
newact.sa_handler = do_sigchild;
newact.sa_flags = 0;
sigemptyset(&newact.sa_mask);
//避免出现僵尸进程的情况:指定父进程回收子进程
//sigaction(SIGCHLD, &newact,NULL);
listen(lfd, 128);
while(1)
{
socklen_t cli_addr_len = sizeof(cli_addr);
cfd = accept(lfd, (struct sockaddr *)&cli_addr, &cli_addr_len);
printf("client connect server\n");
pid = fork();
if(0 == pid)
{
//子进程
close(lfd);
while(1)
{
read_size = read(cfd, buf, sizeof(buf));
if(read_size == 0)
{
printf("client has been closed\n");
break;
}
printf("read content:%s\n",buf);
memset(buf,0,sizeof(buf));
}
printf("child pcb return \n");
close(cfd);
return 0;
}else if(pid > 0)
{
//父进程
close(cfd);
continue;
}else
{
printf("fork error\n");
}
}
close(lfd);
return 0;
}
测试结果:
二、多线程并发服务器
设计思路:多线程服务器跟多进程服务器的思路其实一样,当有client发生连接时,服务器会调用accept跟client发生连接,并创建子线程来跟client通信。
代码如下:
#include "stdio.h"
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVER_PORT (8888)
typedef struct
{
struct sockaddr_in cli_addr;
int cfd;
}cliInfo_t;
void *task(void * arg)
{
cliInfo_t * pCliInfo = (cliInfo_t *)arg;
char ipAddr[10] = {0};
int cli_port = 0;
int read_size = 0;
char buf[1024] = {0};
inet_ntop(AF_INET, &(pCliInfo ->cli_addr.sin_addr), ipAddr, sizeof(ipAddr));
printf("client ip addr : %s\n",ipAddr);
cli_port = ntohs(pCliInfo ->cli_addr.sin_port);
printf("client port : %d\n",cli_port);
//子线程分离,防止产生僵尸线程
pthread_detach(pthread_self());
while(1)
{
read_size = read(pCliInfo ->cfd, buf, sizeof(buf));
if(read_size == 0)
{
printf("client closed\n");
break;
}
printf("receive data from client:%s",buf);
memset(buf,0,sizeof(buf));
}
close(pCliInfo ->cfd);
return NULL;
}
int main(void)
{
int lfd = -1;
int cfd = -1;
struct sockaddr_in ser_sock_addr, cli_sock_addr;
socklen_t cli_addr_len = sizeof(cli_sock_addr);
pthread_t tid;
cliInfo_t cliInfo[100];
int i = 0;
int ret = -1;
lfd = socket(AF_INET,SOCK_STREAM,0);
ser_sock_addr.sin_family = AF_INET;
ser_sock_addr.sin_port = htons(SERVER_PORT);
ser_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(lfd, (struct sockaddr *)&ser_sock_addr,sizeof(ser_sock_addr));
if(ret < 0)
{
printf("bind error \n");
return -1;
}
listen(lfd, 30);
while(1)
{
cfd = accept(lfd, (struct sockaddr *)&cli_sock_addr, &cli_addr_len);
cliInfo[i].cli_addr = cli_sock_addr;
cliInfo[i].cfd = cfd;
//当有客户端跟服务器发生连接时,创建子线程跟客户端数据通信
pthread_create(&tid, NULL,task, (void *)&cliInfo[i]);
i++;
}
return 0;
}
测试结果:
现象其实跟多进程服务器的现象是一样的。