一 Socket编程
1 TCP客户端/服务器模型
#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#define SERV_PORT 8888
int main(){
int sfd,cfd;
socklen_t cli_addr_len;
struct sockaddr_in serv_addr,cli_addr;
int n,i;
char buf[BUFSIZ],str[BUFSIZ];
sfd = socket(AF_INET,SOCK_STREAM,0); //建立TCP的socket
bzero(&serv_addr,sizeof(serv_addr)); //清零
serv_addr.sin_family = AF_INET; //构建 ip + port
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)); //绑定 ip和port
listen(sfd,128); //定义支持128个请求连接
printf("Accepting connection...\n");
cli_addr_len = sizeof(cli_addr);
cfd = accept(sfd,(struct sockaddr *)&cli_addr,&cli_addr_len); //阻塞等待接收客户端的socket连接
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&cli_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(cli_addr.sin_port));
while(1){
n = read(cfd,buf,sizeof(buf)); //读取socket
for(i=0 ; i<n ; i++){
buf[i] = toupper(buf[i]); //小写转大写
}
write(cfd,buf,n); //写回socket
write(STDOUT_FILENO,buf,n); //写到屏幕
}
close(cfd); //关闭client 的socket
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<strings.h>
#include<string.h>
#define SERV_PORT 8888
#define SERV_IP "127.0.0.1"
int main(){
int cfd;
struct sockaddr_in cli_addr;
char str[BUFSIZ],buf[BUFSIZ];
cfd = socket(AF_INET,SOCK_STREAM,0);
int n;
bzero(&cli_addr,sizeof(cli_addr));
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET,SERV_IP,&cli_addr.sin_addr.s_addr);
connect(cfd,(struct sockaddr *)&cli_addr,sizeof(cli_addr));
while(1){
fgets(str,sizeof(str),stdin);
write(cfd,str,strlen(str));
n = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,n);
}
close(cfd);
return 0;
}
2 UDP客户端/服务器模型
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#include<ctype.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define SERVER_PORT 8888
int main(){
int sockfd;
struct sockaddr_in server_addr,client_addr;
socklen_t client_addr_len;
int n,i;
char buf[BUFSIZ],str[INET_ADDRSTRLEN];
sockfd = socket(AF_INET,SOCK_DGRAM,0);
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
printf("accept connection...\n");
while(1){
client_addr_len = sizeof(client_addr);
n = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&client_addr,&client_addr_len);
if(n == -1){
perror("recvfrom error");
exit(1);
}
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(client_addr.sin_port));
for(i=0 ; i<n ; i++){
buf[i] = toupper(buf[i]);
}
n = sendto(sockfd,buf,n,0,(struct sockaddr*)&client_addr,sizeof(client_addr));
if(n == -1){
perror("sendto error");
exit(1);
}
}
close(sockfd);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#define SERVER_PORT 8888
#define SERVER_IP "127.0.0.1"
int main(){
int sockfd;
struct sockaddr_in server_addr;
char buf[BUFSIZ];
int n;
sockfd = socket(AF_INET,SOCK_DGRAM,0);
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET,SERVER_IP,&server_addr.sin_addr.s_addr);
while((fgets(buf,sizeof(buf),stdin))!=NULL){
n = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&server_addr,sizeof(server_addr));
if( n == -1){
perror("sendto error");
exit(1);
}
n = recvfrom(sockfd,buf,sizeof(buf),0,NULL,0);
if( n== -1){
perror("recvfrom error");
exit(1);
}
write(STDOUT_FILENO,buf,n);
}
close(sockfd);
return 0;
}
二 高并发服务器
1 多进程并发服务器
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<strings.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
#define SERVER_PORT 8888
#define SERVER_IP "127.0.0.1"
void do_signal(int num){
while(waitpid(0,NULL,WNOHANG)>0);
}
int main(){
int server_fd,client_fd;
struct sockaddr_in server_addr,client_addr;
socklen_t client_addr_len;
char buf[BUFSIZ],str[BUFSIZ];
int n,i;
pid_t pid;
struct sigaction act;
act.sa_handler = do_signal;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD,&act,NULL); //信号捕捉,避免产生僵尸进程
server_fd = socket(AF_INET,SOCK_STREAM,0);
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET,SERVER_IP,&server_addr.sin_addr.s_addr);
bind(server_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
listen(server_fd,128);
printf("Accept Connection...\n");
while(1){
client_addr_len = sizeof(client_addr);
client_fd =accept(server_fd,(struct sockaddr*)&client_addr,&client_addr_len);
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(client_addr.sin_port));
pid = fork(); //fork子进程
if(pid < 0) {
perror("fork error");
exit(1);
}else if(pid == 0){ //子进程
close(server_fd); //关闭server端socket文件描述符
while(1){
n = read(client_fd,buf,sizeof(buf));
if(n == 0){ //client端关闭
printf("the other side has been closed.\n");
break;
}
for(i=0 ; i<n ; i++){
buf[i] = toupper(buf[i]);
}
write(client_fd,buf,n);
write(STDOUT_FILENO,buf,n);
}
close(client_fd);
return 0;
}else{ //父进程
close(client_fd); //关闭client端socket文件描述符
}
}
close(server_fd);
return 0;
}
2 多线程并发服务器
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>
#include<strings.h>
#include<pthread.h>
#define SERVER_PORT 8888
#define SERVER_IP "127.0.0.1"
struct msg{ //封装传入线程处理函数的参数
struct sockaddr_in client_addr;
int client_fd;
};
void* do_thread(void * arg){ //线程处理函数
char buf[BUFSIZ],str[BUFSIZ];
struct msg *ts = (struct msg*)arg; //获取参数
int n,i;
pthread_detach(pthread_self()); //线程分离,避免产生僵尸线程
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&ts->client_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(ts->client_addr.sin_port));
while(1){
n = read(ts->client_fd,buf,sizeof(buf));
if(n == 0){
printf("the other side has been closed.\n");
break;
}
for(i=0 ; i<n ; i++){
buf[i] = toupper(buf[i]);
}
write(ts->client_fd,buf,n);
write(STDOUT_FILENO,buf,n);
}
close(ts->client_fd);
}
int main(){
int server_fd,client_fd;
struct sockaddr_in server_addr,client_addr;
socklen_t client_addr_len;
int n,i=0;
struct msg client_collection[BUFSIZ];
pthread_t ptid;
server_fd = socket(AF_INET,SOCK_STREAM,0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET,SERVER_IP,&server_addr.sin_addr.s_addr);
bind(server_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
listen(server_fd,128);
printf("Accept Connection...\n");
while(1){
client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd,(struct sockaddr*)&client_addr,&client_addr_len);
client_collection[i].client_addr = client_addr;
client_collection[i].client_fd = client_fd;
pthread_create(&ptid,NULL,do_thread,(void*)&client_collection[i]); //创建线程
i++;
}
close(server_fd);
return 0;
}
3 多路I/O转接服务器
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<strings.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<unistd.h>
#define SERVER_PORT 8888
#define SERVER_IP "127.0.0.1"
int main(){
int server_fd,client_fd,sockfd;
int n,i;
struct sockaddr_in server_addr,client_addr;
socklen_t client_addr_len;
char buf[BUFSIZ],str[FD_SETSIZE];
fd_set rset,allset;
int maxfd,maxi;
int nready,client[FD_SETSIZE];
server_fd = socket(AF_INET,SOCK_STREAM,0);
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET,SERVER_IP,&server_addr.sin_addr.s_addr);
bind(server_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
listen(server_fd,128);
maxfd = server_fd;
maxi = -1;
for(i=0 ; i<FD_SETSIZE ; i++){
client[i] = -1;
}
FD_ZERO(&allset);// 构造select监控文件描述符集
FD_SET(server_fd,&allset);
while(1){
rset = allset;//每次循环时都从新设置select监控信号集
nready = select(maxfd+1,&rset,NULL,NULL,NULL);
if(nready < 0 ){
perror("select error");
exit(1);
}
if(FD_ISSET(server_fd,&rset)){
client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd,(struct sockaddr*)&client_addr,&client_addr_len);
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(client_addr.sin_port));
for(i=0 ; i<FD_SETSIZE ; i++){
if(client[i] < 0 ){
client[i] = client_fd; //保存accept返回的文件描述符到client里
break;
}
}
if(i == FD_SETSIZE){ //达到select能监控的文件个数上限 1024
printf("too many clients\n");
exit(1);
}
FD_SET(client_fd,&allset);//添加一个新的文件描述符到监控信号集里
if(client_fd > maxfd){
maxfd = client_fd; // select第一个参数需要
}
if(i > maxi){
maxi = i; //更新client[]最大下标值
}
if(--nready == 0){
continue; // 如果没有更多的就绪文件描述符继续回到上面select阻塞监听
}
}
for(i=0 ; i<=maxi ; i++){ //检测哪个clients 有数据就绪
if((sockfd = client[i])<0){
continue;
}
if(FD_ISSET(sockfd,&rset)){
if((n = read(sockfd,buf,sizeof(buf)))==0){
close(sockfd); //当client关闭链接时,服务器端也关闭对应链接
FD_CLR(sockfd,&allset);// 解除select监控此文件描述符
client[i] = -1;
printf("client[%d] closed connection\n",i);
}else{
int j;
for(j=0 ; j<n ; j++){
buf[j] = toupper(buf[j]);
}
write(sockfd,buf,n);
}
if(--nready == 0){
break;
}
}
}
}
close(server_fd);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#include<ctype.h>
#include<sys/socket.h>
#include<poll.h>
#include<arpa/inet.h>
#include<errno.h>
#define SERVER_PORT 8888
#define SERVER_IP "127.0.0.1"
#define OPEN_MAX 1024
int main(){
int server_fd,client_fd,sockfd;
int n,i;
struct sockaddr_in server_addr,client_addr;
socklen_t client_addr_len;
struct pollfd client[OPEN_MAX];
char buf[BUFSIZ],str[INET_ADDRSTRLEN];
int maxi,nready;
server_fd = socket(AF_INET,SOCK_STREAM,0);
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET,SERVER_IP,&server_addr.sin_addr.s_addr);
bind(server_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
listen(server_fd,128);
client[0].fd = server_fd;
client[0].events = POLLIN; //监听普通读事件
for(i=1 ; i<OPEN_MAX; i++){
client[i].fd = -1; //用-1初始化client[]里剩下元素
}
maxi = 0; //client[]数组有效元素中最大元素下标
while(1){
nready = poll(client,maxi+1,-1);
if(client[0].revents & POLLIN){ //有客户端链接请求
client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd,(struct sockaddr*)&client_addr,&client_addr_len);
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(client_addr.sin_port));
for(i=0 ; i<OPEN_MAX ; i++){
if(client[i].fd < 0){ //找到client[]中空闲的位置,存放accept返回
client[i].fd = client_fd;
break;
}
}
if(i == OPEN_MAX){
printf("too many clients\n");
exit(1);
}
client[i].events = POLLIN; //监控读事件
if(i > maxi){ //更新client[]中最大元素下标
maxi = i;
}
if(--nready == 0){ //没有更多就绪事件时,继续回到poll阻塞
continue;
}
}
for(i=1 ; i<=maxi ; i++){
if((sockfd = client[i].fd)<0){
continue;
}
if(client[i].revents & POLLIN){
if((n = read(sockfd,buf,sizeof(buf)))<0){
if(errno == ECONNRESET){ //当收到 RST标志时
printf("client[%d] aborted connection\n",i);
close(sockfd);
client[i].fd = -1;
}
}else if(n == 0){
printf("client[%d] closed connection\n",i);
close(sockfd);
client[i].fd = -1;
}else{
int j;
for(j = 0 ; j<n ; j++){
buf[j] = toupper(buf[j]);
}
write(sockfd,buf,n);
}
if(--nready == 0){
break;
}
}
}
}
close(server_fd);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#include<ctype.h>
#include<sys/socket.h>
#include<sys/epoll.h>
#include<arpa/inet.h>
#define SERVER_PORT 8888
#define SERVER_IP "127.0.0.1"
#define OPEN_MAX 1024
int main(){
int server_fd,client_fd,sockfd;
int efd,nready,res;
int n,i,j,maxi;
struct sockaddr_in server_addr,client_addr;
socklen_t client_addr_len;
char buf[BUFSIZ],str[INET_ADDRSTRLEN];
struct epoll_event tep,ep[OPEN_MAX];
int client[OPEN_MAX];
server_fd = socket(AF_INET,SOCK_STREAM,0);
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(server_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
listen(server_fd,128);
for(i=0 ;i<OPEN_MAX ; i++){
client[i] = -1;
}
maxi = -1;
efd = epoll_create(OPEN_MAX);
if(efd == -1){
perror("epoll_create error");
exit(1);
}
tep.events = EPOLLIN;
tep.data.fd = server_fd;
res = epoll_ctl(efd,EPOLL_CTL_ADD,server_fd,&tep);
if(res == -1){
perror("epoll_ctl");
exit(1);
}
while(1){
nready = epoll_wait(efd,ep,OPEN_MAX,-1);
if(nready == -1){
perror("epoll_wait error");
exit(1);
}
for(i = 0 ; i<nready ; i++){
if(!(ep[i].events & EPOLLIN)){
continue;
}
if(ep[i].data.fd == server_fd){
client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd,(struct sockaddr*)&client_addr,&client_addr_len);
printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,str,sizeof(str)),ntohs(client_addr.sin_port));
for(j = 0 ; j<OPEN_MAX ; j++){
if(client[j]<0){
client[j] = client_fd;
break;
}
}
if(j == OPEN_MAX){
printf("too many client\n");
exit(1);
}
if(j > maxi){
maxi = j;
}
tep.events = EPOLLIN;
tep.data.fd = client_fd;
res = epoll_ctl(efd,EPOLL_CTL_ADD,client_fd,&tep);
if(res == -1){
perror("epoll_ctl");
exit(1);
}
}else{
sockfd = ep[i].data.fd;
n = read(sockfd,buf,sizeof(buf));
if(n == 0){
for(j=0 ; j<OPEN_MAX ; j++){
if(client[j] == sockfd){
client[j] = -1;
break;
}
}
res = epoll_ctl(efd,EPOLL_CTL_DEL,sockfd,NULL);
if(res == -1){
perror("epoll_ctl error");
exit(1);
}
close(sockfd);
printf("client[%d] closed connection\n",j);
}else{
for(j=0 ; j<n ; j++){
buf[j] = toupper(buf[j]);
}
write(sockfd,buf,n);
}
}
}
}
close(server_fd);
close(efd);
return 0;
}