Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】

2023-05-16

Socket编程

目前较为流行的网络编程模型是客户机/服务器通信模式

客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求。如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服务器进程B1同时为客户进程A1、A2和B2提供服务。

Socket概述

①   所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过“套接字”向网络发出请求或者应答网络请求。

②   Socket是连接运行在网络上的两个程序间的双向通信的端点。

③   网络通讯其实指的就是Socket间的通讯。

④   通讯的两端都有Socket,数据在两个Socket之间通过IO来进行传输。

套接字socket的类型

(1)流式套接字(SOCK_STREAM)

提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收(TCP协议)

(2)数据报式套接字(SOCK_DGRAM)

提供无连接服务,数据包以独立包形式发送,不提供无措保证,数据可能丢失,并且接收顺序混乱(UDP协议)

(3)原始套接字(SOCK_RAM)

套接字(socket)

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

随着Unix的应用推广,套接字有被引进了windows等操作系统。套接字通常只与同一区域的套接字交换数据,windows socket只支持一个通信区域:网际域(AF_INET),这个域被使用忘记协议簇的通信进程使用。

基于UDP(面向无连接)的socket编程

报式传输:“客户端”,1.socket()函数;2.bind()函数,绑定客户端的地址与端口【网络间通信AF_STREAM】或者路径【进程间通信AF_DGRAM】,以便于后续服务端sendto()函数参数的填写。若服务器端只是收不发数据,即,服务端有recvfrom()函数无sendto()函数,则客户端不需要bind()函数;若服务端要发送数据,即,有sendto()函数,则客户端需要bind()函数; 3.客户端sendto()函数参数,填写服务端的地址与端口【网络间通信AF_STREAM】或者服务端路径【进程间通信AF_DGRAM】的结构体地址与结构体长度,服务端必须有bind()函数;4.客户端recvfrom()函数参数,NULL,会自动识别。

报式传输:“服务端”,1.socket()函数;2.bind()函数,绑定客户端的地址与端口【网络间通信AF_STREAM】或者路径【进程间通信AF_DGRAM】,以便于后续客户端sendto()函数参数的填写。若服务器端只是收不发数据,即,服务端有recvfrom()函数无sendto()函数,则客户端不需要bind()函数;3.服务端sendto()函数参数,填写客户端的地址与端口【网络间通信AF_STREAM】或者客户端路径【进程间通信AF_DGRAM】的结构体地址与结构体长度,服务端必须有bind()函数;4.recvfrom()函数参数,NULL,会自动识别。

基于UDP(面向无连接)的socket编程(循环监听)——流式套接字(SOCK_STREAM)
进程间通信AF_UNIX,典型的本地进程间通信

服务器:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

int main()
{
	int iSocketFD = 0;
	int iNewFD = 0;
	struct sockaddr_un stLocalAddr = {0};
	char acBuf[1024]= {0};

	iSocketFD = socket(AF_UNIX, SOCK_STREAM, 0);
	if(0 > iSocketFD)	
	{
		printf("创建socket失败!\n");
		return 0;
	}

	stLocalAddr.sun_family = AF_UNIX;
	sprintf(stLocalAddr.sun_path, "./xxx");

	remove("./xxx");

	if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
	{
		close(iSocketFD);
		printf("绑定地址失败!\n");
		return -1;
	}

	if(0 > listen(iSocketFD, 5))
	{
		close(iSocketFD);
		printf("监听失败!\n");
		return -1;
	}

	while(1)
	{
		iNewFD = accept(iSocketFD, NULL, NULL);
		if(0 > iNewFD)
		{
			close(iSocketFD);
			printf("接收数据失败!\n");
			return -1;
		}
		if(0 > recv(iNewFD, acBuf, sizeof(acBuf), 0))
		{
			close(iSocketFD);
			close(iNewFD);
			printf("接收失败!\n");
			return -1;
		}
		else
		{
			printf("接收到的客户端发来的信息是:%s\n", acBuf);
		}

		if(0 > send(iNewFD, "服务器",  sizeof("服务器"), 0))
		{
			close(iSocketFD);
			close(iNewFD);
			printf("发送失败!\n");
			return -1;
		}
	}
	return 0;
}

客户端:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>

int main()
{
	int iSocketFD = 0;
	struct sockaddr_un stRemoteAddr = {0};	
	char acBuf[1024] = {0};
 
	iSocketFD = socket(AF_UNIX, SOCK_STREAM, 0);
	if(0 > iSocketFD)
	{
		printf("创建socket失败!\n");
		return -1;
	}

	//填充对端地址
	stRemoteAddr.sun_family = AF_UNIX;
	sprintf(stRemoteAddr.sun_path,"./xxx"); //注意用sprintf
	
	//注意connect的第二个参数
	if(0 > connect(iSocketFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
	{
		close(iSocketFD);
		printf("连接服务器失败!\n");
		return -1;
	}	
	
	if(0 > send(iSocketFD, "客户端", sizeof("客户端"), 0))
	{
		close(iSocketFD);
		printf("发送数据失败!\n");
		return -1;
	}
	
	if(0 > recv(iSocketFD, acBuf, sizeof(acBuf), 0))
	{
		close(iSocketFD);
		printf("接收数据失败!\n");
		return -1;
	}

	printf("客户端接收到服务器发来的消息是:%s\n", acBuf);
	
	return 0;
}

测试:

1、编译服务器、客户端代码:

[root@localhost unix_stream]# make socket_client_stream
cc     socket_client_stream.c   -o socket_client_stream
[root@localhost unix_stream]# make socket_server_stream
cc     socket_server_stream.c   -o socket_server_stream

2、执行服务端代码:

[root@localhost unix_stream]# ./socket_server_stream
接收到的客户端发来的信息是:客户端
接收到的客户端发来的信息是:客户端

3、执行客户端代码:

[root@localhost unix_stream]# ./socket_client_stream
客户端接收到服务器发来的消息是:服务器
[root@localhost unix_stream]# ./socket_client_stream
客户端接收到服务器发来的消息是:服务器

 

 

基于UDP(面向无连接)的socket编程——数据报式套接字(SOCK_DGRAM)
进程间通信AF_UNIX,典型的本地进程间通信

服务器:(  循环监听)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

int main()
{
	int iSocketFD = 0;
	int iNewFD = 0;
	struct sockaddr_un stLocalAddr = {0};
	struct sockaddr_un stRemoteAddr = {0};
	char acBuf[1024]= {0};

	iSocketFD = socket(AF_UNIX, SOCK_DGRAM, 0);
	if(0 > iSocketFD)	
	{
		printf("创建socket失败!\n");
		return 0;
	}

	stLocalAddr.sun_family = AF_UNIX;
	sprintf(stLocalAddr.sun_path, "./server");
	remove("./server");//绑定之前要删除原来的文件
	if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
	{
		close(iSocketFD);
		printf("绑定地址失败!\n");
		return -1;
	}

	stRemoteAddr.sun_family = AF_UNIX;
	sprintf(stRemoteAddr.sun_path, "./client");

	while(1)
	{
		if(0 > recvfrom(iSocketFD, acBuf, sizeof(acBuf), 0, NULL, NULL))
		{
			close(iSocketFD);
			printf("接收失败!\n");
			return -1;
		}
		else
		{
			printf("接收到的客户端发来的信息是:%s\n", acBuf);
		}

		if(0 > sendto(iSocketFD, "服务器", sizeof("服务器"), 0, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
		{
			close(iSocketFD);
			printf("发送失败!\n");
			return -1;
		}
	}
	return 0;
}

客户端:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>

int main()
{
	int iSocketFD = 0;
	struct sockaddr_un stRemoteAddr = {0};	
	struct sockaddr_un stLocalAddr = {0};	
	char acBuf[1024] = {0};
 
	iSocketFD = socket(AF_UNIX, SOCK_DGRAM, 0);
	if(0 > iSocketFD)
	{
		printf("创建socket失败!\n");
		return -1;
	}

	stLocalAddr.sun_family = AF_UNIX;
	sprintf(stLocalAddr.sun_path, "./client"); //注意用sprintf			
	remove("./client");	//绑定之前要删除原来的
	if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
	{
		printf("绑定地址失败!\n");
		return -1;
	}

	//填充对端地址
	//报式传输,只发不收可以不bind,要发要收必须要bind
	stRemoteAddr.sun_family = AF_UNIX;
	sprintf(stRemoteAddr.sun_path, "./server"); //注意用sprintf			

	if(0 > sendto(iSocketFD, "客户端", sizeof("客户端"), 0, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
	{
		close(iSocketFD);
		printf("发送数据失败!\n");
		return -1;
	}
	
	if(0 > recvfrom(iSocketFD, acBuf, sizeof(acBuf), 0, NULL, NULL))
	{
		close(iSocketFD);
		printf("接收数据失败!\n");
		return -1;
	}

	printf("客户端接收到服务器发来的消息是:%s\n", acBuf);
	
	return 0;
}

测试:

1、编译服务器和客户端:

[root@localhost unix_dgram]# make socket_client_dgram
cc     socket_client_dgram.c   -o socket_client_dgram
[root@localhost unix_dgram]# make socket_server_dgram
cc     socket_server_dgram.c   -o socket_server_dgram

2、服务器监听:

[root@localhost unix_dgram]# ./socket_server_dgram
接收到的客户端发来的信息是:客户端
接收到的客户端发来的信息是:客户端

3、客户端连接服务器:

[root@localhost unix_dgram]# ./socket_client_dgram
客户端接收到服务器发来的消息是:服务器
[root@localhost unix_dgram]# ./socket_client_dgram
客户端接收到服务器发来的消息是:服务器

参考链接:https://blog.csdn.net/zhang___yong/article/details/78702559

java:https://www.cnblogs.com/wzy330782/p/5479833.html

基于TCP/IP和UDP协议的socket编程结构解析:https://blog.csdn.net/zhengnice/article/details/51428080

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】 的相关文章

随机推荐