一、什么是socket?
Socket的英文原义是“孔”或“插座” 。在编程中,Socket被称做套接字,是网络通信中的一种约定 。Socket编程的应用无处不在,我们平时用的QQ、微信、浏览器等程序,都与Socket编程有关 。我们平时使用浏览器查资料自动获取的ip地址冲突,这个过程的技术原理是怎样的呢?
我们平时使用浏览器 , 大致就是这样的一个过程 。这里有两个重要的名词:服务端与客户端 。
Socket编程的目的就是如何实现这两端之间的通信 。
1、Socket编程在嵌入式中也很重要
Socket编程不仅仅在互联网方面很重要,在我们的嵌入式方面也是非常的重要,因为现在很多电子设备都趋向于联网 。比如很多嵌入式工作的招聘要求都会有这一条要求:
说一点题外话,还在学校的朋友,如果感觉到很迷茫,不知道学什么的时候 , 可以上招聘网站上看看自己未来工作相关的职位的任职要求 , 这样就可以总结自己的一些不足、比较有针对性的去学习 。
二、Socket编程中的几个重要概念
Socket编程用于解决我们客户端与服务端之间通信的问题 。我们平时多多少少都有听过IP地址、端口、TCP协议、UDP协议等概念,这些都与Socket编程中相关,想要知道怎么用起来,当然得先了解它们的一些介绍 。下面看一下这些专业术语的一些要点介绍:
1、什么是IP地址?
IP地址(Internet Protocol Address)是指互联网协议地址 , 又译为网际协议地址 。IP地址被用来给Internet上的电脑一个编号 。我们可以把“个人电脑”比作“一台电话” , 那么“IP地址”就相当于“电话号码” 。若计算机1知道计算机2的IP地址,则计算机1就能访问计算机2 。
IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节) 。IP地址通常用点分十进制表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数 。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110) 。
IP地址有IPv4与IPv6之分,现在用得较多的是IPv4 。其中,有一个特殊的IP地址需要我们记?。?27.0.0.1,这是回送地址,即本地机,一般用来测试使用 。后边我们的实例中会用到 。
关于IP地址还有很多知识要点,但是对于在Socket编程中的应用,我们暂且知道这么多就可以 。
2、什么是TCP/IP端口?
上一点中我们提到自动获取的ip地址冲突,若计算机1知道计算机2的IP地址,则计算机1就能访问计算机2 。但是,我们要访问计算机2中的不同的应用软件,则还得需要一个信息:端口 。端口使用16bit进行编号,即其范围为:0~65536 。但0~1023 的端口一般由系统分配给特定的服务程序,例如 Web 服务的端口号为 80,FTP 服务的端口号为 21等 。
3、什么是协议?
协议(Protocol)是通信双方进行数据交互的一种约定 。如TCP、UDP协议:
(1)TCP协议
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,数据可以准确发送 , 数据丢失会重发 。TCP协议常用于web应用中 。
TCP连接(三次握手)
TCP传输起始时,客户端、服务端要完成三次数据交互工作才能建立连接,常称为三次握手 。可形象比喻为如下对话:
客户端:服务端您好 , 我有数据要发给你,请求您开通访问权限 。
服务端:客户端您好 , 已给您开通权限,您可以发送数据了 。
客户端:收到,谢谢 。
具体示意图为:
这里的SYN和ACK是都是标志位,其中SYN代表新建一个连接,ACK代表确认 。其中m、n都是随机数 。具体说明如:
TCP断开(四次挥手)
TCP断开连接时 , 客户端、服务端要完成四次数据交互工作才能建立连接 , 常称为四次挥手 。可形象比喻为如下对话:
客户端:服务端您好,我发送数据完毕了,即将和您断开连接 。
服务端:客户端您好,我稍稍准备一下,再给您断开
服务端:客户端您好,我准备好了,您可以断开连接了 。
客户端:好的,合作愉快!
具体示意图为:
这里的FIN也是一个标志位,代表断开连接 。具体说明类似三次握手 。
为什么建立连接只需要三次数据交互,而断开连接需要四次呢?
建立连接时,服务端在监听状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端 。
而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接 , 因此,己方ACK和FIN一般都会分开发送 。
(2)UDP协议
UDP(User Datagram Protocol , 用户数据报协议)是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务 , 可以保证通讯效率,传输延时小 。例如视频聊天应用中用的就是UDP协议,这样可以保证及时丢失少量数据,视频的显示也不受很大影响 。
4、什么是协议族?
协议族是多个协议的统称 。比如我们的TCP/IP协议族,其不仅仅是TCP协议、IP协议 , 而是多个协议的集合,其包含IP、TCP、UDP、FTP、SMTP等协议 。
三、socket编程的API接口1、Linux下的socket API接口(1)创建socket:socket()函数
函数原型:
int socket(int af, int type, int protocol);
使用示例:
创建TCP套接字:
int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
创建UDP套接字:
int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
(2)绑定套接字:bind()函数
函数原型:
int bind(int sock, struct sockaddr *addr, socklen_t addrlen);
使用示例:
将创建的套接字ServerSock与本地IP127.0.0.1、端口1314进行绑定:
/* 创建服务端socket */int ServerSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);?/* 设置服务端信息 */struct sockaddr_in ServerSockAddr;memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));// 给结构体ServerSockAddr清零ServerSockAddr.sin_family = PF_INET;// 使用IPv4地址ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 本机IP地址ServerSockAddr.sin_port = htons(1314);// 端口?/* 绑定套接字 */bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR));
其中struct sockaddr_in类型的结构体变量用于保存IPv4的IP信息 。若是IPv6,则有对应的结构体:
struct sockaddr_in6 {sa_family_t sin6_family;// 地址类型,取值为AF_INET6in_port_t sin6_port;// 16位端口号uint32_t sin6_flowinfo;// IPv6流信息struct in6_addr sin6_addr;// 具体的IPv6地址uint32_t sin6_scope_id;// 接口范围ID};
(3)建立连接:connect()函数
函数原型:
int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);
参数与bind()的参数类似 。
使用示例:
int ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);connect(ClientSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR));
(4)监听:listen()函数
函数原型:
int listen(int sock, int backlog);
使用示例:
/* 进入监听状态 */listen(ServerSock, 10);
(5)接收请求:accept()函数
函数原型:
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
使用示例:
/* 监听客户端请求,accept函数返回一个新的套接字,发送和接收都是用这个套接字 */int ClientSock = accept(ServerSock, (SOCKADDR*)&ClientAddr, &len);
(6)关闭:close()函数
函数原型:
int close(int fd);
使用示例:
close(ServerSock);
(7)数据的接收和发送
数据收发函数有几组:
函数原型:
ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
这里介绍一下recv()/send()、recvfrom()/sendto() 。
recv()函数:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
send()函数:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
recvfrom()函数:
ssize_t recvfrom(int sock, void *buf, size_t nbytes, int flags, struct sockadr *from, socklen_t *addrlen);
sendto()函数:
ssize_t sendto(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen);
2、windows下的socket API接口
跟Linux下的差不多:
SOCKET socket(int af, int type, int protocol);int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen);int listen(SOCKET sock, int backlog);SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen); int closesocket( SOCKET s);int send(SOCKET sock, const char *buf, int len, int flags);int recv(SOCKET sock, char *buf, int len, int flags);int recvfrom(SOCKET sock, char *buf, int nbytes, int flags, const struct sockaddr *from, int *addrlen);int sendto(SOCKET sock, const char *buf, int nbytes, int flags, const struct sockadr *to, int addrlen);
3、TCP、UDP通信的socket编程过程图
(1)TCP通信socket编程过程
(2)UDP通信socket编程过程
四、socket的应用实例1、基于TCP的本地客户端、服务端信息交互实例
本例的例子实现的功能为:本地TCP客户端往本地TCP服务端发送数据 , TCP服务端收到数据则会打印输出,同时把原数据返回给TCP客户端 。这个例子类似于我们在做单片机的串口实验时,串口上位机往我们的单片机发送数据,单片机收到数据则把该数据原样返回给上位机 。
(1)windows的程序:
服务端程序tcp_server.c:
#include #include #define BUF_LEN100int main(void){ WSADATA wd; SOCKET ServerSock, ClientSock; char Buf[BUF_LEN] = {0}; SOCKADDR ClientAddr; SOCKADDR_IN ServerSockAddr; int addr_size = 0, recv_len = 0;/* 初始化操作sock需要的DLL */ WSAStartup(MAKEWORD(2,2),&wd);/* 创建服务端socket */ if (-1 == (ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) {printf("socket error!n");exit(1); }/* 设置服务端信息 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));// 给结构体ServerSockAddr清零ServerSockAddr.sin_family = AF_INET;// 使用IPv4地址ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 本机IP地址ServerSockAddr.sin_port = htons(1314);// 端口/* 绑定套接字 */if (-1 == bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR))) {printf("bind error!n");exit(1); }/* 进入监听状态 */ if (-1 == listen(ServerSock, 10)) {printf("listen error!n");exit(1); }addr_size = sizeof(SOCKADDR); while (1) {/* 监听客户端请求 , accept函数返回一个新的套接字 , 发送和接收都是用这个套接字 */if (-1 == (ClientSock = accept(ServerSock, (SOCKADDR*)&ClientAddr, &addr_size))){printf("socket error!n");exit(1);}/* 接受客户端的返回数据 */int recv_len = recv(ClientSock, Buf, BUF_LEN, 0);printf("客户端发送过来的数据为:%sn", Buf);/* 发送数据到客户端 */send(ClientSock, Buf, recv_len, 0);/* 关闭客户端套接字 */closesocket(ClientSock);/* 清空缓冲区 */memset(Buf, 0, BUF_LEN);} /*如果有退出循环的条件 , 这里还需要清除对socket库的使用*/ /* 关闭服务端套接字 */ //closesocket(ServerSock);/* WSACleanup();*/ return 0;}
客户端程序tcp_client.c:
#include #include #define BUF_LEN100int main(void){ WSADATA wd; SOCKET ClientSock; char Buf[BUF_LEN] = {0}; SOCKADDR_INServerSockAddr;/* 初始化操作sock需要的DLL */ WSAStartup(MAKEWORD(2,2),&wd);/* 向服务器发起请求 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));ServerSockAddr.sin_family = AF_INET;ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");ServerSockAddr.sin_port = htons(1314);while (1) {/* 创建客户端socket */if (-1 == (ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))){printf("socket error!n");exit(1);}if (-1 == connect(ClientSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR))){printf("connect error!n");exit(1);}printf("请输入一个字符串,发送给服务端:");gets(Buf);/* 发送数据到服务端 */send(ClientSock, Buf, strlen(Buf), 0);/* 接受服务端的返回数据 */recv(ClientSock, Buf, BUF_LEN, 0);printf("服务端发送过来的数据为:%sn", Buf);memset(Buf, 0, BUF_LEN);// 重置缓冲区closesocket(ClientSock);// 关闭套接字 }// WSACleanup();/*如果有退出循环的条件,这里还需要清除对socket库的使用*/ return 0;}
我们上边的IP地址概念那一部分中 , 有强调127.0.0.1这个IP是一个特殊的IP地址,这是回送地址,即本地机,一般用来测试使用 。这个例子中我们就用到了 。此外,端口我们设置为1314,这是随意设置的,只要范围在1024~65536之间就可以 。
本文使用的是gcc编译器编译,编译命令如下:
gcc tcp_client.c -o tcp_client.exe -lwsock32gcc tcp_server.c -o tcp_server.exe -lwsock32
这里必须要加-lwsock32这个参数用于链接windows下socket编程必须的winsock2这个库 。若是使用集成开发环境,则需要把wsock32.lib放在工程目录下,并在我们代码中#include下面加上一行 #pragma comment(lib, “ws2_32.lib”)代码(这种情况本人未验证,有兴趣的朋友可尝试) 。
实验现象:
先启动服务端程序tcp_server.exe,再启动客户端程序tcp_client.exe , 并在客户端中输入字符串,则当服务端会接收到字符串时会打印输出,与此同时也会往客户端返回相同的数据:
(2)Linux的程序:
在linux下 , “一切都是文件”,所以这里我们的套接字也当做文件来看待 。
服务端程序linux_tcp_server.c:
#include #include #include #include #include #include #include #define BUF_LEN100int main(void){ int ServerFd, ClientFd;char Buf[BUF_LEN] = {0}; struct sockaddr ClientAddr; int addr_len = 0, recv_len = 0; struct sockaddr_in ServerSockAddr;int optval = 1;/* 创建服务端文件描述符 */ if (-1 == (ServerFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) {printf("socket error!n");exit(1); }/* 设置服务端信息 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));// 给结构体ServerSockAddr清零ServerSockAddr.sin_family = AF_INET;// 使用IPv4地址ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);// 自动获取IP地址ServerSockAddr.sin_port = htons(6666);// 端口// 设置地址和端口号可以重复使用if (setsockopt(ServerFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {printf("setsockopt error!n");exit(1); }/* 绑定操作,绑定前加上上面的socket属性可重复使用地址 */if (-1 == bind(ServerFd, (struct sockaddr*)&ServerSockAddr, sizeof(struct sockaddr))) {printf("bind error!n");exit(1); }/* 进入监听状态 */ if (-1 == (listen(ServerFd, 10))) {printf("listen error!n");exit(1); }addr_len = sizeof(struct sockaddr); while (1) {/* 监听客户端请求,accept函数返回一个新的套接字,发送和接收都是用这个套接字 */if (-1 == (ClientFd = accept(ServerFd, (struct sockaddr*)&ClientAddr, &addr_len))){printf("accept error!n");exit(1);}/* 接受客户端的返回数据 */if ((recv_len = recv(ClientFd, Buf, BUF_LEN, 0)) < 0){printf("recv error!n");exit(1);}printf("客户端发送过来的数据为:%sn", Buf);/* 发送数据到客户端 */send(ClientFd, Buf, recv_len, 0);/* 关闭客户端套接字 */close(ClientFd);/* 清空缓冲区 */memset(Buf, 0, BUF_LEN);} return 0;}
客户端程序linux_tcp_client.c:
#include #include #include #include #include #include #define BUF_LEN100int main(void){ int ClientFd; char Buf[BUF_LEN] = {0}; struct sockaddr_inServerSockAddr;/* 向服务器发起请求 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));ServerSockAddr.sin_family = AF_INET;ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");ServerSockAddr.sin_port = htons(6666);while (1) {/* 创建客户端socket */if (-1 == (ClientFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))){printf("socket error!n");exit(1);}/* 连接 */if (-1 == connect(ClientFd, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr))){printf("connect error!n");exit(1);}printf("请输入一个字符串,发送给服务端:");gets(Buf);/* 发送数据到服务端 */send(ClientFd, Buf, strlen(Buf), 0);memset(Buf, 0, BUF_LEN);// 重置缓冲区/* 接受服务端的返回数据 */recv(ClientFd, Buf, BUF_LEN, 0);printf("服务端发送过来的数据为:%sn", Buf);memset(Buf, 0, BUF_LEN);// 重置缓冲区close(ClientFd);// 关闭套接字 }return 0;}
Linux下编译就不需要添加-lwsock32参数:
gcc linux_tcp_server.c -o linux_tcp_servergcc linux_tcp_client.c -o linux_tcp_client
实验现象:
在调试这份程序时 , 出现了绑定错误:
经上网查询发现是端口重复使用 , 可以在调用bind()函数之前调用setsockopt()函数以解决端口重复使用的问题:
2、基于UDP的本地客户端、服务端信息交互实例
(1)windows的程序
服务端程序udp_server.c:
#include #include #define BUF_LEN100int main(void){ WSADATA wd; SOCKET ServerSock; char Buf[BUF_LEN] = {0}; SOCKADDR ClientAddr; SOCKADDR_IN ServerSockAddr; int addr_size = 0;/* 初始化操作sock需要的DLL */ WSAStartup(MAKEWORD(2,2),&wd);/* 创建服务端socket */ if(-1 == (ServerSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {printf("socket error!n");exit(1); }/* 设置服务端信息 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));// 给结构体ServerSockAddr清零ServerSockAddr.sin_family = AF_INET;// 使用IPv4地址ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);// 自动获取IP地址ServerSockAddr.sin_port = htons(1314);// 端口/* 绑定套接字 */if (-1 == (bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))) {printf("bind error!n");exit(1); }addr_size = sizeof(SOCKADDR); while (1) {/* 接受客户端的返回数据 */int str_len = recvfrom(ServerSock, Buf, BUF_LEN, 0, &ClientAddr, &addr_size);printf("客户端发送过来的数据为:%sn", Buf);/* 发送数据到客户端 */sendto(ServerSock, Buf, str_len, 0, &ClientAddr, addr_size);/* 清空缓冲区 */memset(Buf, 0, BUF_LEN);} /*如果有退出循环的条件 , 这里还需要清除对socket库的使用*/ /* 关闭服务端套接字 */ //closesocket(ServerSock);/* WSACleanup();*/ return 0;}
客户端程序udp_client.c:
#include #include #define BUF_LEN100int main(void){ WSADATA wd; SOCKET ClientSock; char Buf[BUF_LEN] = {0}; SOCKADDR ServerAddr; SOCKADDR_INServerSockAddr; int ServerAddrLen = 0;/* 初始化操作sock需要的DLL */ WSAStartup(MAKEWORD(2,2),&wd);/* 创建客户端socket */ if (-1 == (ClientSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {printf("socket error!n");exit(1); }/* 向服务器发起请求 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));ServerSockAddr.sin_family = PF_INET;ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");ServerSockAddr.sin_port = htons(1314);ServerAddrLen = sizeof(ServerAddr);while (1) {printf("请输入一个字符串 , 发送给服务端:");gets(Buf);/* 发送数据到服务端 */sendto(ClientSock, Buf, strlen(Buf), 0, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr));/* 接受服务端的返回数据 */recvfrom(ClientSock, Buf, BUF_LEN, 0, &ServerAddr, &ServerAddrLen);printf("服务端发送过来的数据为:%sn", Buf);memset(Buf, 0, BUF_LEN);// 重置缓冲区 }closesocket(ClientSock);// 关闭套接字 // WSACleanup();/*如果有退出循环的条件,这里还需要清除对socket库的使用*/ return 0;}
(2)Linux下的程序
服务端程序linux_udp_server.c:
#include #include #include #include #include #include #include #define BUF_LEN100int main(void){ int ServerFd; char Buf[BUF_LEN] = {0}; struct sockaddr ClientAddr; struct sockaddr_in ServerSockAddr; int addr_size = 0;int optval = 1;/* 创建服务端socket */ if ( -1 == (ServerFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {printf("socket error!n");exit(1); }/* 设置服务端信息 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));// 给结构体ServerSockAddr清零ServerSockAddr.sin_family = AF_INET;// 使用IPv4地址ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);// 自动获取IP地址ServerSockAddr.sin_port = htons(1314);// 端口// 设置地址和端口号可以重复使用if (setsockopt(ServerFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {printf("setsockopt error!n");exit(1); }/* 绑定操作,绑定前加上上面的socket属性可重复使用地址 */if (-1 == bind(ServerFd, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr))) {printf("bind error!n");exit(1); }addr_size = sizeof(ClientAddr); while (1) {/* 接受客户端的返回数据 */int str_len = recvfrom(ServerFd, Buf, BUF_LEN, 0, &ClientAddr, &addr_size);printf("客户端发送过来的数据为:%sn", Buf);/* 发送数据到客户端 */sendto(ServerFd, Buf, str_len, 0, &ClientAddr, addr_size);/* 清空缓冲区 */memset(Buf, 0, BUF_LEN);}close(ServerFd); return 0;}
客户端程序linux_udp_client.c:
#include #include #include #include #include #include #define BUF_LEN100int main(void){ int ClientFd; char Buf[BUF_LEN] = {0}; struct sockaddr ServerAddr; int addr_size = 0; struct sockaddr_inServerSockAddr;/* 创建客户端socket */ if (-1 == (ClientFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {printf("socket error!n");exit(1); }/* 向服务器发起请求 */memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));ServerSockAddr.sin_family = PF_INET;ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");ServerSockAddr.sin_port = htons(1314);addr_size = sizeof(ServerAddr);while (1) {printf("请输入一个字符串,发送给服务端:");gets(Buf);/* 发送数据到服务端 */sendto(ClientFd, Buf, strlen(Buf), 0, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr));/* 接受服务端的返回数据 */recvfrom(ClientFd, Buf, BUF_LEN, 0, &ServerAddr, &addr_size);printf("服务端发送过来的数据为:%sn", Buf);memset(Buf, 0, BUF_LEN);// 重置缓冲区 }close(ClientFd);// 关闭套接字return 0;}
实验现象:
实验现象如实例1 。
五、总结
本笔记简单介绍了一些与socket编程相关的一些知识点:IP地址 , 什么是端口 , 协议等 。重点介绍了TCP、UDP通信的一些原理及其API接口的用法,并给出了windows和linux下的TCP、UDP通信实例 。以上就是关于socket编程的一些总结,如有错误 , 欢迎指出!
【TCP、UDP通信总结】本文到此结束 , 希望对大家有所帮助!
猜你喜欢
- 男女之间的「暧昧」是从哪些方面偷偷开始的?
- ?四月份还会下暴雨冰雹吗 四月份下暴雨正常吗
- 二 热爱生活,每天折腾一点之
- 如何衡量一款家电是否优秀?博西家电用德系精工打磨产品艺术
- 突发!西安一男子坠楼,无辜幼童被砸中,经抢救无效,双双去世!
- 我曾是贫困生——qianning
- 三生三世
- 上海医生杀妻事件,疑原因只是怀疑妻子肚子里的孩子是别人的
- 网上的段子,小伙当真去“勾搭”富婆想“少走弯路”,结果被教育
