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

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通信流程


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

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

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

例程:

服务器

#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本地通信



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

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




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;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值