在Linux网络编程中,一般建立在两端之间,服务器端和客户端。客户端是面向用户的应用,而服务器端要处理客户端所提出的请求。通常一个服务器要面向多个客户端,保证对每个客户端都能高效的处理,这时候需要并发操作。实现并发控制的方法有两个,一个是并发服务器,另一个是多路复用I/O,现在就给大家介绍一下这两种方法。
方法一:并发服务器
这个方法可以通过进程(线程)来实现,主要根据子进程(子线程)之间并行运行的特点。将对客户端请求的处理工作,交于子进程(子线程)来处理,达到一个服务器同时处理多个客户端的效果。
1、这是通过(子)进程来实现的。
<span style="font-size:14px;font-weight: normal;">------------------------- server.c -------------------------
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(){
int sockfd, newfd, r;
struct sockaddr_in myaddr;
struct sockaddr_in fromaddr;
socklen_t len = 16;
char buf[100] = {0};
pid_t pid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(5666);
myaddr.sin_addr.s_addr = inet_addr("192.168.80.128");
r = bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr));
if(listen(sockfd, 10) < 0){
perror("listen");
return -1;
}
while(1){
printf("the server is listenning..................\n");
newfd = accept(sockfd, &fromaddr, &len);
if(newfd > 0){
printf("accept done! newfd = %d\n",newfd);
}
pid = fork();
if(pid == 0){
while(1){
r = recv(newfd, buf, 100, 0);
if(r < 0){
perror("recv")
break;
}
printf("%d: %s\n", newfd, buf);
bzero(buf, strlen(buf));
}
close(newfd);
bzero(&fromaddr, strlen(fromaddr));
exit(0);
}else if(pid < 0)
exit(0);
}
}</span>
2、这是通过线程实现的
<span style="font-size:14px;font-weight: normal;">------------------------- server.c -------------------------
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(){
int sockfd, newfd, r;
struct sockaddr_in myaddr;
struct sockaddr_in fromaddr;
socklen_t len = 16;
char buf[100] = {0};
pid_t pid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(5666);
myaddr.sin_addr.s_addr = inet_addr("192.168.80.128");
r = bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr));
if(listen(sockfd, 10) < 0){
perror("listen");
return -1;
}
while(1){
printf("the server is listenning..................\n");
newfd = accept(sockfd, &fromaddr, &len);
if(newfd > 0){
printf("accept done! newfd = %d\n",newfd);
}
pid = fork();
if(pid == 0){
while(1){
r = recv(newfd, buf, 100, 0);
if(r < 0){
perror("recv")
break;
}
printf("%d: %s\n", newfd, buf);
bzero(buf, strlen(buf));
}
close(newfd);
bzero(&fromaddr, strlen(fromaddr));
exit(0);
}else if(pid < 0)
exit(0);
}
}</span>
<pre name="code" class="cpp" style="font-weight: bold;"><span style="font-weight: normal;"><span style="font-size:14px;">------------------------- server.c -------------------------
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h></span></span>
#include <pthread.h>void *fun(void *p){int fd = *((int *)p);char buf[100] = {0};int r;printf("pthread fd = %d start\n", fd);while(1){r = recv(fd, buf, 100, 0);if(r <= 0){printf("客户端已退出 %d\n", fd);break;}printf("%d: %s\n", fd, buf);bzero(buf, strlen(buf));}close(fd);}int main(){int sockfd, newfd, r;struct sockaddr_in myaddr;struct sockaddr fromaddr;socklen_t len=16;char buf[100] = {0};pthread_t tid;sockfd = socket(AF_INET, SOCK_STREAM, 0);myaddr.sin_family = AF_INET;myaddr.sin_port = htons(5666);myaddr.sin_addr.s_addr = inet_addr(192.168.80.128);r = bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr));if(listen(sockfd, 10) < 0){perror("listen");return -1;}while(1){newfd = accept(sockfd, &fromaddr, &len);printf("newfd = %d \n", newfd);pthread_creat(&tid, NULL, fun, &newfd);}close(sockfd);}
<span style="font-size:18px;">注意:由于</span><span style="font-size:14px; color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; line-height: 24px; text-indent: 28px;">pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库。</span>
<span style="font-size:14px; color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;"><span style="font-family:SimSun;">#gcc server_xian.c -o server_xian -pthread</span><span style="font-family:arial, 宋体, sans-serif;">
</span></span>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(){
int sockfd,r;
char buf[100] = {0};
struct sockaddr_in toaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
printf("sockfd = %d\n", sockfd);
toaddr.sin_family = AF_INET;
toaddr.sin_port = htons(5666);
toaddr.sin_addr.s_addr = inet_addr("192.168.80.128");
r = connect(sockfd, (struct sockaddr *)&toaddr, sizeof(toaddr));
if(r == -1){ perror("connect "); return -1; }
printf("connect OK\n");
while(1){
scanf("%s", buf);
send(sockfd, buf, strlen(buf), 0);
}
close(sockfd);
}