c语言学习5==TCP和socket

本文详细介绍了如何使用socket实现不同服务器上的进程间通信,涉及网络字节序的转换、IPV4套接字结构体以及TCP套接字的创建与监听。同时,通过对比多进程和线程版并发服务器的实现,展示了两种并发模型的差异和应用场景。
摘要由CSDN通过智能技术生成

socket实现不同服务器上的进程间的通信。

socket是一个伪文件,分成两个部分:读缓冲区和写缓冲区。所以socket一旦建立就会在PCB中对应生成一个文件描述符fd。

 

 socket必须成对出现。

=============================

网络字节序:

大小端:小端,低位存低地址,高位存高地址。大端相反。

总之在网络间传递的包都是大端。

 网络字节序和主机字节序的转换

点分十进制转网络大端

#include <stdio.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
//准备转换成大端的IP地址
	char buf[]="192.168.136.101";
	unsigned int num=0;
//转成大端
	inet_pton(AF_INET,buf,&num);
	unsigned char * p=(unsigned char *)&num;
	printf("%d %d %d %d\n",*p,*(p+1),*(p+2),*(p+3));
//大端转小端
	char ip[16]="";
	printf("%s\n",inet_ntop(AF_INET,&num,ip,16));
	return 0;
}

IPV4套接字结构体

 我们需要指定的就是协议 IP 端口,将这三个东西封装成一个结构体

man 7 ip

IPV4套接字结构体       

   struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET 协议 */
               in_port_t      sin_port;   /* port in network byte order 端口*/
               struct in_addr sin_addr;   /* internet address IP地址*/
           };

           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };
 

通用套接字结构体

TCP特点:出错重传,每次发送数据对方都会回ACK,可靠。

socket服务器编写


#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
	//创建套接字/文件描述符
	int lfd = socket(AF_INET,SOCK_STREAM,0);
	//绑定。将协议和端口转成大端封装进结构体
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8000);
	//	addr.sin_addr.s_addr = INADDR_ANY;//绑定的是通配地址
	//此处将文件描述符绑定到本服务器的IP地址
	inet_pton(AF_INET,"192.168.136.101",&addr.sin_addr.s_addr);
	int ret = bind(lfd,(struct sockaddr *)&addr,sizeof(addr));
	if(ret < 0)
	{
		perror("");
		exit(0);

	}
	//监听
	listen(lfd,128);
	//提取
	struct sockaddr_in cliaddr;
	socklen_t len = sizeof(cliaddr);
	int cfd = accept(lfd,(struct sockaddr *)&cliaddr,&len);
	char ip[16]="";
	printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,
				ip,16),	ntohs(cliaddr.sin_port));
	//读写
	char buf[1024]="";
	while(1)
	{
		bzero(buf,sizeof(buf));
	//	int n = read(STDIN_FILENO,buf,sizeof(buf));
	//	write(cfd,buf,n);
		int n =0;
		n = read(cfd,buf,sizeof(buf));
		if(n ==0 )//如果read返回等于0,代表对方关闭 
		{
			printf("client close\n");
			break;
		}
		printf("%s\n",buf);
	
	}
	//关闭
	close(lfd);
	close(cfd);
	return 0;
}


三次握手

多进程实现并发服务器

与线程版进行对比

 gcc 02_process_tcp_server.c wrap.c


#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "wrap.h"
void free_process(int sig)
{
	pid_t pid;
	while(1)
	{
		pid = waitpid(-1,NULL,WNOHANG);
		if(pid <=0 )//小于0 子进程全部退出了 =0没有进程没有退出
		{
			break;
		}
		else
		{
			printf("child pid =%d\n",pid);
		}
	}



}
int main(int argc, char *argv[])
{
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set,SIGCHLD);
	sigprocmask(SIG_BLOCK,&set,NULL);
	//创建套接字,绑定
	int lfd = tcp4bind(8008,NULL);
	//监
	Listen(lfd,128);
	//提取
	//回射
	struct sockaddr_in cliaddr;
	socklen_t len = sizeof(cliaddr);
	while(1)
	{
		char ip[16]="";
		//提取连接,
		int cfd = Accept(lfd,(struct sockaddr *)&cliaddr,&len);
		printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
				ntohs(cliaddr.sin_port));
		//fork创建子进程
		pid_t pid;
		pid = fork();
		if(pid < 0)
		{
			perror("");
			exit(0);
		}
		else if(pid == 0)//子进程
		{
			//关闭lfd
			close(lfd);
			while(1)
			{
			char buf[1024]="";

			int n = read(cfd,buf,sizeof(buf));
			if(n < 0)
			{
				perror("");
				close(cfd);
				exit(0);
			}
			else if(n == 0)//对方关闭j
			{
				printf("client close\n");
				close(cfd);
				exit(0);
			
			}
			else
			{
				printf("%s\n",buf);
				write(cfd,buf,n);
			//	exit(0);	
			}
			}
		
		}
		else//父进程
		{
			close(cfd);
			//回收
			//注册信号回调
			struct sigaction act;
			act.sa_flags =0;
			act.sa_handler = free_process;
			sigemptyset(&act.sa_mask);
			sigaction(SIGCHLD,&act,NULL);
			sigprocmask(SIG_UNBLOCK,&set,NULL);
		
		}
	}
	//关闭



	return 0;
}


1

2

3

线程版服务器

#include <stdio.h>
#include <pthread.h>
#include "wrap.h"

typedef struct c_info
{
	int cfd;
	struct sockaddr_in cliaddr;
}CINFO;
void* client_fun(void *arg);
int main(int argc, char *argv[]){
	if(argc<2)
	{
		printf("argc<2 >>>> \n ./a.out 8000 \n");
		return 0;
	}
	short port=atoi(argv[1]);
	int lfd=tcp4bind(port,NULL);
	Listen(lfd,128);
	struct sockaddr_in cliaddr;
	socklen_t len=sizeof(cliaddr);
	CINFO *info;
	while(1){
		int cfd=Accept(lfd,(struct sockaddr *)&cliaddr,&len);
		char ip[16]="";
		printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
				ntohs(cliaddr.sin_port)
		      );
		pthread_t pthid;
		info=malloc(sizeof(CINFO));
		info->cfd=cfd;
		info->cliaddr=cliaddr;
	
		pthread_create(&pthid,NULL,client_fun,info);
	}
	return 0;


}

void* client_fun(void *arg)
{
	CINFO *info=(CINFO *)arg;
	char ip[16]="";

	printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16),
			ntohs(info->cliaddr.sin_port));
	while(1)
	{
		char buf[1024]="";
		int count=0;
		count =read(info->cfd,buf,sizeof(buf));
		if(count<0)
		{
			printf("client close\n");
			break;	
		}
		else if (count==0)
		{
			printf("clent close\n");
			break;
		}
		else
		{
			printf("%s\n",buf);
			write(info->cfd,buf,count);
		}
	}
	close(info->cfd);
	free(info);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值