Linux网络编程

一 Socket编程

1 TCP客户端/服务器模型

  • server端
#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;
}
  • client端
#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客户端/服务器模型

  • server
#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;
}
  • client
#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 多进程并发服务器

  • server端
#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;
}
  • client端(同上)

2 多线程并发服务器

  • server端
#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;
}
  • client端(同上)

3 多路I/O转接服务器

  • select
#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;
}
  • poll
#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;
}
  • epoll
#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城老湿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值