欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux学习(二十七):TCP/IP网络编程之本地通信

程序员文章站 2022-05-14 08:06:57
...

1、介绍

       在Linux学习(二十):进程通信时讲过,socket通信也可以用于进程间通信,之前几章讲的都是用于网络间通信,今天介绍以下socket的本地通信
         创建套接字时使用本地协议PF_UNIX(或PF_LOCAL)。分为流式套接字和用户数据报套接字。和其他进程间通信方式相比使用方便、效率更高常用于前后台进程通信。
本地地址结构

       struct sockaddr_un        // <sys/un.h>

        {

             sa_family_t  sun_family;

             char  sun_path[108];         // 套接字文件的路径

         };

填充地址结构

    struct sockaddr_un myaddr;

     bzero(&myaddr,  sizeof(myaddr));

     myaddr.sun_family = AF_UNIX;

     strcpy(myaddr.sun_path,  “mysocket”);

2、socket本地通信流程

        2.1 TCP通信流程

Linux学习(二十七):TCP/IP网络编程之本地通信

1.除了地址类型不同外,其他和TCP套接字的使用方法完全一样

2.绑定套接字文件时,会自动创建该文件。若文件已存在则无法绑定。可以在调用bind前先用remove删除

Linux学习(二十七):TCP/IP网络编程之本地通信

客户端同网络编程时一样,本地地址不用显示的指定

例程:

服务器

#include <stdio.h>  //printf
#include <arpa/inet.h>  //inet_addr htons
#include <sys/types.h>
#include <sys/socket.h>  //socket bind listen accept connect
#include <stdlib.h>  //exit
#include <unistd.h>  //close
#include <string.h>
#include <sys/un.h> //sockaddr_un

#define N 128
#define errlog(errmsg) do{\
							perror(errmsg);\
							printf("%s --> %s --> %d\n", __FILE__, __func__, __LINE__);\
							exit(1);\
						 }while(0)

int main(int argc, const char *argv[])
{
	int sockfd, acceptfd;
	struct sockaddr_un serveraddr, clientaddr;
	socklen_t addrlen = sizeof(serveraddr);
	char buf[N] = {};
	ssize_t bytes;

	//第一步:创建套接字
	if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
	{
		errlog("fail to socket");
	}

	//第二步:填充服务器本地信息结构体
	serveraddr.sun_family = AF_UNIX;
	strcpy(serveraddr.sun_path, argv[1]);

	//第三步:将套接字域网络信息结构体绑定
	if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		errlog("fail to bind");
	}

	//第四步:将套接字设置为监听状态
	if(listen(sockfd, 5) < 0)
	{
		errlog("fail to listen");
	}

	//第五步:阻塞等待客户端的连接请求
	if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
	{
		errlog("fail to accept");
	}

	while(1)
	{
		if((bytes = recv(acceptfd, buf, N, 0)) < 0)
		{
			errlog("fail to recv");
		}
		else if(bytes == 0)
		{
			printf("NO DATA\n");
			exit(1);
		}
		else 
		{
			if(strncmp(buf, "quit", 4) == 0)
			{
				printf("client is quited ...\n");
				break;
			}
			else
			{
				printf("client : %s\n", buf);

				strcat(buf, " *_*");

				if(send(acceptfd, buf, N, 0) < 0)
				{
					errlog("fail to send");
				}
			}
		}
	}

	close(acceptfd);
	close(sockfd);
	
	return 0;
}
服务器会显示的创建一个套接字文件(还记得7种文件类型吗?)

客户端:

#include <stdio.h>  //printf
#include <arpa/inet.h>  //inet_addr htons
#include <sys/types.h>
#include <sys/socket.h>  //socket bind listen accept connect
#include <stdlib.h>  //exit
#include <unistd.h>  //close
#include <string.h>
#include <sys/un.h> //sockaddr_un

#define N 128
#define errlog(errmsg) do{\
							perror(errmsg);\
							printf("%s --> %s --> %d\n", __FILE__, __func__, __LINE__);\
							exit(1);\
						 }while(0)

int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_un serveraddr;
	socklen_t addrlen = sizeof(serveraddr);
	char buf[N] = {};

	//第一步:创建套接字
	if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
	{
		errlog("fail to socket");
	}

	//第二步:填充服务器本地信息结构体
	serveraddr.sun_family = AF_UNIX;
	strcpy(serveraddr.sun_path, argv[1]);

	//第三步:发送客户端的连接请求
	if(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
	{
		errlog("fail to connect");
	}

	while(1)
	{
		fgets(buf, N, stdin);
		buf[strlen(buf) - 1] = '\0';

		if(send(sockfd, buf, N, 0) < 0)
		{
			errlog("fail to send");
		}

		if(strncmp(buf, "quit", 4) == 0)
		{
			printf("client quit ...\n");
			break;
		}
		else
		{
			if(recv(sockfd, buf, N, 0) < 0)
			{
				errlog("fail to recv");
			}

			printf("server : %s\n", buf);
		}
	}

	close(sockfd);
	
	return 0;
}

2.2 UDP本地通信


Linux学习(二十七):TCP/IP网络编程之本地通信

1.除了地址类型不同外,其他和UDP套接字的使用方法完全一样

2.绑定套接字文件时,会自动创建该文件。若文件已存在则无法绑定。可以在调用bind前先用remove删除


Linux学习(二十七):TCP/IP网络编程之本地通信

1.若客户端没有绑定地址(套接字文件),系统不会自动分配
2.客户端没有绑定地址,只能发送数据,不能接收数据,网络通信时可以不绑定,因为发送时会带上本机IP地址,但本地通信时不会自动分配套接字文件,必须帮当才能接收数据
服务器:
#include <stdio.h>  //printf
#include <arpa/inet.h>  //inet_addr htons
#include <sys/types.h>
#include <sys/socket.h>  //socket bind listen accept connect
#include <stdlib.h>  //exit
#include <unistd.h>  //close
#include <string.h>
#include <sys/un.h>  //sockaddr_un

#define N 128
#define errlog(errmsg) do{\
							perror(errmsg);\
							printf("%s --> %s --> %d\n", __FILE__, __func__, __LINE__);\
							exit(1);\
						 }while(0)

int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_un serveraddr, clientaddr;
	socklen_t addrlen = sizeof(serveraddr);
	char buf[N] = {};
	ssize_t bytes;

	//第一步:创建套接字
	if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
	{
		errlog("fail to socket");
	}

	//第二步:填充服务器本地信息结构体
	serveraddr.sun_family = AF_UNIX;
	strcpy(serveraddr.sun_path, argv[1]);

	//第三步:将套接字域网络信息结构体绑定
	if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		errlog("fail to bind");
	}

	while(1)
	{
		if((bytes = recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
		{
			errlog("fail to recvfrom");
		}
		else if(bytes == 0)
		{
			printf("NO DATA\n");
			exit(1);
		}
		else 
		{
			if(strncmp(buf, "quit", 4) == 0)
			{
				printf("client is quited ...\n");
				break;
			}
			else
			{
				printf("clientaddr.sun_path = %s\n", clientaddr.sun_path);
				printf("client : %s\n", buf);

				strcat(buf, " *_*");

				if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&clientaddr, addrlen) < 0)
				{
					errlog("fail to sendto");
				}
			}
		}
	}

	close(sockfd);
	
	return 0;
}


客户端
#include <stdio.h>  //printf
#include <arpa/inet.h>  //inet_addr htons
#include <sys/types.h>
#include <sys/socket.h>  //socket bind listen accept connect
#include <stdlib.h>  //exit
#include <unistd.h>  //close
#include <string.h>
#include <sys/un.h>  //sockaddr_un

#define N 128
#define errlog(errmsg) do{\
							perror(errmsg);\
							printf("%s --> %s --> %d\n", __FILE__, __func__, __LINE__);\
							exit(1);\
						 }while(0)

int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_un serveraddr, clientaddr;
	socklen_t addrlen = sizeof(serveraddr);
	char buf[N] = {};

	//第一步:创建套接字
	if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
	{
		errlog("fail to socket");
	}

	//第二步:填充服务器本地信息结构体
	serveraddr.sun_family = AF_UNIX;
	strcpy(serveraddr.sun_path, argv[1]);

	clientaddr.sun_family = AF_UNIX;
	strcpy(clientaddr.sun_path, argv[2]);
	
	if(bind(sockfd, (struct sockaddr *)&clientaddr, addrlen) < 0)
	{
		errlog("fail to bind"); 
	}

	while(1)
	{
		fgets(buf, N, stdin);
		buf[strlen(buf) - 1] = '\0';

		if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&serveraddr, addrlen) < 0)
		{
			errlog("fail to sendto");
		}

		if(strncmp(buf, "quit", 4) == 0)
		{
			printf("client quit ...\n");
			break;
		}
		else
		{
			if(recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&serveraddr, &addrlen) < 0)
			{
				errlog("fail to recvfrom");
			}

			printf("server : %s\n", buf);
		}
	}

	close(sockfd);
	
	return 0;
}








相关标签: 通信