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_streamccsocket_client_stream.c -o socket_client_stream[root@localhost unix_stream]# make socket_server_streamccsocket_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"); //注意用sprintfremove("./client");//绑定之前要删除原来的if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr))){printf("绑定地址失败!\n");return -1;}//填充对端地址//报式传输,只发不收可以不bind,要发要收必须要bindstRemoteAddr.sun_family = AF_UNIX;sprintf(stRemoteAddr.sun_path, "./server"); //注意用sprintfif(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_dgramccsocket_client_dgram.c -o socket_client_dgram[root@localhost unix_dgram]# make socket_server_dgramccsocket_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客户端接收到服务器发来的消息是:服务器
参考链接:/zhang___yong/article/details/78702559
java:/wzy330782/p/5479833.html
基于TCP/IP和UDP协议的socket编程结构解析:/zhengnice/article/details/51428080
Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】
如果觉得《Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报》对你有帮助,请点赞、收藏,并留下你的观点哦!