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

};

相关推荐
A小辣椒13 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒17 小时前
TShark:基础知识
linux
AlfredZhao19 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux