基于UDP/TCP的 c/s 通信模型

基于UDP c/s通信模型

  • 客户端(socket;sendto ...)
  • 服务器端 ---把自己的地址公布出去 (socket;bind //绑定; recvfrom ...)

1.recvfrom函数:

ssize_t recvfrom( int sockfd, //socket的fd

void *buf, //保存数据的一块空间的地址

size_t len, //这块空间的大小

int flags, // 0 默认的接收方式 --- 阻塞方式

struct sockaddr *src_addr, //用来保存发送方的地址信息

socklen_t *addrlen //表示发送方实际的地址信息大小 );

返回值:成功:返回接收到的字节数; 失败:-1。

cs 复制代码
struct sockaddr_in srcaddr;
socklen_t addrlen = sizeof(srcaddr);

char buf[1024];
   
while(1)
{
    recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&srcaddr,&addrlen);
        
    printf("IP = %s\n",inet_ntoa(srcaddr.sin_addr));
    printf("post = %d\n",ntohs(srcaddr.sin_port));
    printf("buf = %s\n",buf);
}

2.bind函数:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

(1)功能:如果该函数在服务器端调用,则表示将参数1相关的文件描述符文件与参数2 指定的接口地址关联,用于从该接口接受数据。如果该函数在客户端调用,则表示要将数据从参数1所在的描述符中取出并从参数2所在的接口设备上发送出去。

注意:如果是客户端,则该函数可以省略,由默认接口发送数据。

(2)参数:sockfd之前通过socket函数创建的文件描述符,套接字id; my_addr 是物理接口的结构体指针。表示该接口的信息。

cs 复制代码
struct sockaddr      通用地址结构 --- ip + 端口 
{
    u_short sa_family;  地址族
    char sa_data[14];   地址信息
};


转换成网络地址结构如下:
struct sockaddr_in    ///网络地址结构
{
    u_short           sin_family; //地址族
    u_short           sin_port;   //地址端口
    struct in_addr  sin_addr;   //地址IP  //"192.168.1.123"
    char               sin_zero[8]; //占位
};
 

in_addr_t  === unsigned int 
struct in_addr
{
    in_addr_t s_addr;
}
          

练习:

任务1 从键盘获得数据发给服务器 --fgets

任务2 从服务器不断获取数据打印 --recvfrom

1.客户端:
cs 复制代码
int c_fd = 0;
void child_handler(int signo)
{

	close(c_fd);
    printf("child--exit--\n");
	exit(0);

}

void father_handler(int signo)
{

	close(c_fd);
    printf("father--exit--\n");
	exit(0);
}

int main(int argc, const char *argv[])
{
	//1.socket 创建通信的一端 
	int fd = socket(AF_INET,SOCK_DGRAM,0);

	if (fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	
	printf("fd = %d\n",fd);

	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");

	char buf[1024] = {0};

	//区分任务 
	pid_t pid = fork();

	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	if (pid > 0)
	{
		signal(SIGCHLD,father_handler);
		c_fd = fd;
		while (1)
		{
			printf(">");
			fgets(buf,sizeof(buf),stdin);
			int ret = sendto(fd,buf,strlen(buf)+1,0,(const struct sockaddr *)&seraddr,sizeof(seraddr));
			printf("ret = %d\n",ret);

			if (strncmp(buf,"quit",4) == 0)
			{
				kill(pid,SIGUSR1);
				wait(NULL);
				close(fd);
				exit(0);
			}
		}
		
	}else if (pid == 0) 
	{
		c_fd = fd;
		signal(SIGUSR1,child_handler);
		while (1)
		{
			recvfrom(fd,buf,sizeof(buf),0,NULL,NULL);
			printf("buf = %s\n",buf);

			if (strncmp(buf,"quit",4) == 0)
			{
				close(fd);
				exit(0);
			}
		}
	}
		
	//close(fd); 
	return 0;
}
2.服务器端:
cs 复制代码
int c_fd = 0;
void child_handler(int signo)
{

	close(c_fd);
    printf("child--exit--\n");
	exit(0);

}

void father_handler(int signo)
{

	close(c_fd);
    printf("father--exit--\n");
	exit(0);
}

int main(int argc, const char *argv[])
{

	//1.socket 创建通信的一端 
	int fd = socket(AF_INET,SOCK_DGRAM,0);

	if (fd < 0)
	{
		perror("socket fail");
		return -1;
	}	

	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");
	//2.bind
	if (bind(fd,(struct sockaddr *)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("bind fail");
		return -1;
	}

	struct sockaddr_in srcaddr;
	socklen_t addrlen = sizeof(srcaddr);
	char buf[1024];
	//3.接收数据
	recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&srcaddr,&addrlen);
	printf("--------------------\n");
	printf("IP   = %s\n",inet_ntoa(srcaddr.sin_addr));
	printf("post = %d\n",ntohs(srcaddr.sin_port));
	printf("buf = %s\n",buf);
	printf("--------------------\n");

	pid_t pid = fork();

	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	if (pid > 0)
	{
		signal(SIGCHLD,father_handler);
        c_fd = fd;
		while (1)
		{
			//3.接收数据
			recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&srcaddr,&addrlen);
			printf("--------------------\n");
			printf("IP   = %s\n",inet_ntoa(srcaddr.sin_addr));
			printf("post = %d\n",ntohs(srcaddr.sin_port));
			printf("buf = %s\n",buf);
			printf("--------------------\n");
			
			if (strncmp(buf,"quit",4) == 0)
			{
				kill(pid,SIGUSR1);
				wait(NULL);
				close(fd);
				exit(0);
			}
		}

	}else if (pid == 0)
	{
		signal(SIGUSR1,child_handler);
		while (1)
		{
			printf(">");
			fgets(buf,sizeof(buf),stdin);
			sendto(fd,buf,strlen(buf) + 1, 0, (const struct sockaddr*)&srcaddr,sizeof(srcaddr));
			if (strncmp(buf,"quit",4) == 0)
			{
				close(fd);
				exit(0);
			}
		}
	}	
	
	return 0;
}

基于TCP c/s通信模型

tcp 客户端:

(1)建立连接:

  • socket //买了一部手机;
  • bind //可选 //插上sim卡;
  • connect //拨打电话 ....

(2)通信过程:(read;write;close)

connect函数:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

(1)功能:该函数固定有客户端使用,表示从当前主机向目标主机发起链接请求。

(2)参数:sockfd:本地socket创建的套接子id;addr:程目标主机的地址信息;

addrlen: 参数2的长度。

(3)返回值:成功 0;失败 -1;

cs 复制代码
int main(int argc, const char *argv[])
{
	int fd = socket(AF_INET,SOCK_STREAM,0);

	if (fd < 0)
		handle_error("socket fail");	


	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");

	if (connect(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
		handle_error("connect fail");

	
	return 0;
}

tcp服务器:

(1)建立连接

  • socket //买了一部手机
  • bind //插上sim卡
  • listen //监听 客户端的连接请求
  • accept //接听 ---这一步完成之后 连接就建立好了,之后就可以收发数据

(2)通信过程 (read;write;close)

listen函数:

int listen(int sockfd, int backlog);

accept函数:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

cs 复制代码
int main(int argc, const char *argv[])
{
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);

	if (listen_fd < 0)
		handle_error("socket fail");	


	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50000);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");

	if (bind(listen_fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
		handle_error("bind fail");


	if (listen(listen_fd,5) < 0)
		handle_error("listen fail");


	int connfd = accept(listen_fd,NULL,NULL);

	if (connfd < 0)
		handle_error("accept fail");

	printf("connfd = %d\n",connfd);

	return 0;
}

struct sockaddr *addr //通用地址结构类型,并没有实际去用,实际用到都是具体地址结构类型

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 */

};

/* Internet address. */

struct in_addr {

uint32_t s_addr; /* address in network byte order */

};

相关推荐
tRNA做科研18 分钟前
Bio-Linux-shell详解-1-从0开始
linux·运维·服务器
老汉忒cpp1 小时前
TCP全连接队列和tcpdump抓包
网络·tcp/ip·tcpdump
小黑爱编程1 小时前
【Linux网络】Socket套接字
linux·运维·网络
xyt0_01 小时前
【Linux】常见指令
linux
KookeeyLena71 小时前
udp协议除了打游戏还有什么用途
网络·网络协议·udp
kaixin_啊啊1 小时前
TCP/IP模型成功与OSI模型失败的深层原因:技术、理念与市场化路径的比较
服务器·tcp/ip·php
gs801401 小时前
安装node 报错需要:glibc >= 2.28
linux·服务器·前端·node.js
hgdlip2 小时前
一台电脑对应一个IP地址吗?‌探讨两台电脑共用IP的可能性
服务器·网络协议·tcp/ip·电脑
何老生4 小时前
Linux之MySQL主从复制
linux·运维·mysql
ggdpzhk4 小时前
图片详解,最简单易懂!!!Ubuntu增强功能
linux·ubuntu