一、迭代與并發(fā)服務(wù)器概述
服務(wù)器設(shè)計(jì)技術(shù)有很多具伍,按使用的協(xié)議來(lái)分有 TCP 服務(wù)器和 UDP 服務(wù)器翅雏,按處理方式來(lái)分有迭代服務(wù)器(循環(huán)服務(wù)器)和并發(fā)服務(wù)器。
在網(wǎng)絡(luò)程序里面人芽,一般來(lái)說(shuō)都是許多客戶對(duì)應(yīng)一個(gè)服務(wù)器(多對(duì)一)望几,為了處理客戶的請(qǐng)求,對(duì)服務(wù)端的程序就提出了特殊的要求萤厅。
目前最常用的服務(wù)器模型有:
迭代服務(wù)器:服務(wù)器在同一時(shí)刻只能響應(yīng)一個(gè)客戶端的請(qǐng)求
并發(fā)服務(wù)器:服務(wù)器在同一時(shí)刻可以響應(yīng)多個(gè)客戶端的請(qǐng)求
二橄抹、UDP 迭代服務(wù)器
UDP 循環(huán)服務(wù)器每次從套接字上讀取一個(gè)客戶端的請(qǐng)求 -> 處理 -> 然后將結(jié)果返回給客戶機(jī)。
因?yàn)?UDP 是非面向連接的惕味,沒(méi)有一個(gè)客戶端可以老是占住服務(wù)端楼誓。只要處理過(guò)程不是死循環(huán),或者耗時(shí)不是很長(zhǎng)名挥,服務(wù)器對(duì)于每一個(gè)客戶機(jī)的請(qǐng)求在某種程度上來(lái)說(shuō)是能夠滿足疟羹。
udp迭代服務(wù)器框架:
//1.創(chuàng)建套接字
int sockfd = socket(...);
//2.綁定套接字
bind(...);
while(1)
{
//3.接收客戶端的請(qǐng)求
recvfrom(...);
//4.處理客戶端的請(qǐng)求
process(...);
//5.反饋處理結(jié)果
sendto(...);
}
udp迭代服務(wù)器參考代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
unsigned short port = 8080; //本地端口
//1.創(chuàng)建udp套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0)
{
perror("socket");
exit(-1);
}
// 配置本地網(wǎng)絡(luò)信息
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr)); // 清空
my_addr.sin_family = AF_INET; // IPv4
my_addr.sin_port = htons(port); // 端口
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip
printf("Binding server to port %d\n", port);
// 2.綁定套接字
int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind");
close(sockfd);
exit(-1);
}
printf("receive data...\n");
while(1)
{
int recv_len;
char recv_buf[512] = {0};
struct sockaddr_in client_addr;
char cli_ip[INET_ADDRSTRLEN] = "";//INET_ADDRSTRLEN=16
socklen_t cliaddr_len = sizeof(client_addr);
//3.接收客戶端的請(qǐng)求
recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);
//4.處理客戶端的請(qǐng)求,這里只是把接收過(guò)來(lái)的數(shù)據(jù)打印
inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
printf("\nip:%s ,port:%d\n",cli_ip, ntohs(client_addr.sin_port)); // 客戶端的ip
printf("data(%d):%s\n",recv_len,recv_buf); // 客戶端的數(shù)據(jù)
//5.反饋處理結(jié)果禀倔,這里把接收直接到客戶端的數(shù)據(jù)回復(fù)過(guò)去
sendto(sockfd, recv_buf, recv_len, 0, (struct sockaddr*)&client_addr, cliaddr_len);
}
close(sockfd);
return 0;
}
運(yùn)行結(jié)果:
三榄融、tcp迭代服務(wù)器
TCP 迭代服務(wù)器接受一個(gè)客戶端的連接,然后處理救湖,完成了這個(gè)客戶的所有請(qǐng)求后剃袍,斷開連接。TCP 迭代服務(wù)器一次只能處理一個(gè)客戶端的請(qǐng)求捎谨,只有在這個(gè)客戶的所有請(qǐng)求滿足后民效,服務(wù)器才可以繼續(xù)后面的請(qǐng)求憔维。如果有一個(gè)客戶端占住服務(wù)器不放時(shí),其它的客戶機(jī)都不能工作了畏邢,因此业扒,TCP 服務(wù)器一般很少用迭代服務(wù)器模型的。
tcp迭代服務(wù)器框架:
//1.創(chuàng)建tcp套接字
int sockfd = socket(...);
//2.綁定套接字
bind(...);
//3.監(jiān)聽(tīng)套接字
listen(...);
while(1)
{
//4.提取已連接套接字
int connfd = accept(...);
//5.處理客戶端的請(qǐng)求
process(...);
//6.關(guān)閉已連接套接字
close(connfd);
}
//7.關(guān)閉監(jiān)聽(tīng)套接字
close(sockfd);
tcp迭代服務(wù)器參考代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
unsigned short port = 8080; // 本地端口
//1.創(chuàng)建tcp套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket");
exit(-1);
}
//配置本地網(wǎng)絡(luò)信息
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr)); // 清空
my_addr.sin_family = AF_INET; // IPv4
my_addr.sin_port = htons(port); // 端口
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip
//2.綁定
int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
if( err_log != 0)
{
perror("binding");
close(sockfd);
exit(-1);
}
//3.監(jiān)聽(tīng)舒萎,套接字變被動(dòng)
err_log = listen(sockfd, 10);
if(err_log != 0)
{
perror("listen");
close(sockfd);
exit(-1);
}
printf("listen client @port=%d...\n",port);
while(1)
{
struct sockaddr_in client_addr;
char cli_ip[INET_ADDRSTRLEN] = "";
socklen_t cliaddr_len = sizeof(client_addr);
//4.取出客戶端已完成的連接
int connfd;
connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);
if(connfd < 0)
{
perror("accept");
continue;
}
//5.打印客戶端的ip和端口
inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
printf("----------------------------------------------\n");
printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));
// 接收數(shù)據(jù)
char recv_buf[512] = {0};
int len = recv(connfd, recv_buf, sizeof(recv_buf), 0);
// 處理數(shù)據(jù)程储,這里只是打印接收到的內(nèi)容
printf("\nrecv data:\n");
printf("%s\n",recv_buf);
// 反饋結(jié)果
send(connfd, recv_buf, len, 0);
//6.關(guān)閉已連接套接字
close(connfd);
printf("client closed!\n");
}
//7.關(guān)閉監(jiān)聽(tīng)套接字
close(sockfd);
return 0;
}
運(yùn)行結(jié)果: