网络编程-多进程并发TCP服务器

send函数: 发送数据
原函数:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数:sockfd,是由socket函数返回的套接字描述符
   buf,要发送的数据
   len,要发送的数据的大小
   flags,一个标志位

recv函数: 接收数据
原函数:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:sockfd,由socket函数返回的套接字描述符
   buf,接收数据的存储位置
   len,接收的字节数
   flags,一个标志位

flags 说明 recv send
MSG_DONTROUTE不查路由表yes
MSG_DONTWAIT 本操作不阻塞 yesyes
MSG_OOB发送或接收带外数据yesyes
MSG_WAITALL查看外来消息yes
MSG_PEEK等待所有数据yes

在这里插入图片描述
ps aux|grep server:查看server进程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
 
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
 
 
//最大连接数
#define MAX_LISTEN_QUE 5
//端口号
#define SERV_PORT 8888
//数组的最大字节数
#define MAX_BUFFER_SIZE 100
//创建套接字函数
int mz_ipv4_tcp_create_socket(void)
{
	int listenfd, sockfd, opt = 1;
	struct sockaddr_in server, client;
	socklen_t len;
	int timep;
	int ret;
    //创建套接字
	listenfd = socket(AF_INET, SOCK_STREAM, 0);//IPv4,全双工通信
	if(listenfd < 0)
	{
		perror("Create socket fail.");
		return -1;
	} 
    //设置地址的重用
	if((ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0){
		perror("Error, set socket reuse addr failed");  
		return -1;
	}
    //初始化清零操作
	bzero(&server, sizeof(server));
	server.sin_family = AF_INET;//IPv4
	server.sin_port   = htons(SERV_PORT);//端口号
	server.sin_addr.s_addr  = htonl(INADDR_ANY);//设置为所有都可连接
	//获得结构体地址长度
	len = sizeof(struct sockaddr);
    //套接字与服务器接口绑定
	if(bind(listenfd, (struct sockaddr *)&server, len)<0)
	{
			  perror("bind error.");
		return -1;
	}
	//设置最大连接数  
	listen(listenfd, MAX_LISTEN_QUE);
    //返回套接字
	return listenfd;
}
//数据处理函数
int mz_process_data(int sockfd)
{
	int bytes;
	char buf[MAX_BUFFER_SIZE], read_buf[MAX_BUFFER_SIZE];
    //清空数组
	memset(buf, 0x00, MAX_BUFFER_SIZE);
 
	while(1)
	{
         //清空数组
	    memset(read_buf, 0x00, MAX_BUFFER_SIZE);
		//从通信套接字中接收数据,并存到read_buf中
		bytes = recv(sockfd, read_buf, 100, 0);
		if(bytes < 0)
		{
			printf("read err.\n");
			return -1;
		}
		if(bytes == 0)
		{
			printf("client connection closed.\n");
			return 0;
		}
		printf("Bytes:%lu\n", strlen(read_buf));//打印read_buf的长度
		
        //将读取到的内容发送到通信套接字中
		send(sockfd, read_buf, bytes, 0);
        //比较接收的数据是不是'q'
		if(!strcmp(read_buf, "q"))
		{
			return 0;
		}
         //比较接收的数据是不是'c'
		if(!strcmp(read_buf, "c"))
		{
			printf("i love you.\n");
			sprintf(read_buf, "%s","i love you.\n" );
			send(sockfd, read_buf, 12, 0);
		}
	}
    //关闭通信套接字
	close(sockfd);
	return 0;
}
//信号处理函数
int mz_process_signal(int signo)
{
    //判断信号的类型
	switch(signo)
	{
		case SIGCHLD:
			printf("process_signal\n");
			while(waitpid(-1, NULL, WNOHANG)>0);	
		break;
	}
}
//创建信号处理的句柄
int mz_set_signal_handler(void)
{
	struct sigaction act, oact;
	act.sa_handler = (void *)mz_process_signal;//将信号处理函数的句柄赋值给handler
	sigemptyset(&act.sa_mask);//清空信号集
	act.sa_flags = 0;
	act.sa_flags |= SA_RESTART;
    //定义要处理的信号和处理方法
	if(sigaction(SIGCHLD, &act, &oact) < 0)
	{
		return -1;
	}
		return 0;
}
 
int main(int argc, char *argv[])
{
	int listenfd, sockfd;
	struct sockaddr_in server, client;
	socklen_t len;
	int bytes =0 ;
 
	//调用创建信号句柄函数
	mz_set_signal_handler();
	
	len = sizeof(struct sockaddr);
	//调用套接字处理函数
	listenfd = mz_ipv4_tcp_create_socket();
	
	while(1)
	{
        //服务器等待客户端连接
		sockfd = accept(listenfd, (struct sockaddr *)&client, &len);
		if(sockfd < 0)
		{
			perror("accept error.");
			return -1;
		}
 
		printf("sockfd=%d\n", sockfd);
        //打印客户端地址和端口号
		printf("IP:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs    (client.sin_port));
        //创建子进程
		if(fork() == 0)
		{
            //关闭套接字
			close(listenfd);
            //调用数据处理函数
			mz_process_data(sockfd);
			exit(0);
		}
           //关闭通信套接字
		close(sockfd);
	   
	}
	return 0;
}

运行结果

sockfd=4
IP:192.168.1.10,port:60044
Bytes:1
i love you.
Bytes:1
process_signal

window系统下按win+r,进入cmd,输入telent 192.168.1.12 8888(telnet+IP地址+端口号)进行连接。输入c(通信)或者q(退出)
在这里插入图片描述
client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
        int sockfd;
        struct sockaddr_in servaddr;
        char buf[100],read_buf[100];//存储读取的内容
        int bytes;//存储读取的字节数
 
        if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)//创建套接字
        {
                printf("socket error\n");
                return -1;
        }
        //结构体中成员变量初始化为0     
        bzero(&servaddr,sizeof(servaddr));
        //初始化成员变量
        servaddr.sin_family = AF_INET;//IPv4
        servaddr.sin_addr.s_addr = inet_addr("192.168.1.12");//转换为地址格式
        servaddr.sin_port = htons(8888);//主机序转换到网络序
        //连接服务器
        if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0)//绑定服务器ip和端口到>套结字
        {
                perror("connect error");
                return -2;
        }

		while(1)
		{
			fgets(buf, 100, stdin);

			send(sockfd,buf,strlen(buf),0);
			
			//存储读取的数据和读取的字节数
			bytes = recv(sockfd,read_buf,100,0);
			if(bytes < 0)
       		{
                printf("Error ,read failed\n");
                close(sockfd);
                return -3;
       		}
        	//如果读取的字节数为0 ,就说明连接已经关闭了
        	if(0 == bytes)
        	{
                printf("Server close connection\n");
                close(sockfd);
                return -4;
        	}
        	
        	//打印读取的字节数和读取的内容
        	printf("read bytes %d\n",bytes);
        	printf("read_buf: %s\n",read_buf);
		}
      
        //关闭套结字
        close(sockfd);
        return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值