下面是我的另外一篇文章TCP协议和UDP协议的区别:
https://blog.csdn.net/qq_37941471/article/details/80888827
这样我们可以更清楚的理解程序
UDP服务器和客户端实现需要的接口:
下面介绍的接口都在这个头文件中:
#include <sys/socket.h>
#include <sys/types.h>
1. 创建套接字 ( socket() )
int socket(int domain, int type, int protocol);
int socket(int domain, int type, int protocol);
1.domain 指定使用何种的地址类型
协议 说明
PF_INET/AF_INET Ipv4 网络协议
PF_INET6/AF_INET6 Ipv6 网络协议
2. type的类别。见表:
类型 说明
SOCK_STREAM 提供双向连续且可信赖的数据流, 即TCP
SOCK_DGRAM 使用不连续不可信赖的数据包连接,即UDP
3. protocol 用来指定socket 所使用的传输协议编号,通常为0
4.返回值:成功(0);失败(-1)
5. socket()打开一个网络通讯接口,如果成功的话,就想open()一样返回一个文件描述符
2. 命名套接字
//2. 命名套接字
struct sockaddr_in local;
local.sin_family = AF_INET;//Ipv4: AF_INET;Ipv6: AF_INET6
local.sin_port = htons(atoi(argv[2]));//端口号是2位的数
local.sin_addr.s_addr = inet_addr(argv[1]);
3. 绑定端口号 ( bind() )
int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
1. 返回值:成功(0);失败(-1)
2. 作用:将参数sockfd和myaddr绑定在一起
3. struct sockaddr * :是一个通用的结构体
4. 接受消息 ( recevfrom() )
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);////后面两个参数是 输出型参数
5. 发送消息 ( sento() )
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
函数说明:
sendto() 用来将数据由指定的socket 传给对方主机.
代码实现:
创建下面的文件:
Makefile udp_server.c udp_client.c
Makefile:
.PHONY:all clean
all:udp_server udp_client
udp_server:udp_server.c
gcc $^ -o $@
udp_client:udp_client.c
gcc $^ -o $@
clean:
rm -rf udp_server udp_client
udp_server.c
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
if(argc != 3)
{
printf("Usage:%s ip port\n",argv[0]);
return 1;
}
//1. 创建套接字
int sock = socket(AF_INET, SOCK_DGRAM , 0 );// SOCK_DGRAM 表示UDP
if(sock < 0)
{
perror("socket");
return 2;
}
printf("Socker:%d\n",sock);
//2. 命名套接字
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(argv[2]));//端口号是2位的数
local.sin_addr.s_addr = inet_addr(argv[1]);
//3. 绑定端口号
if( bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0 )
{
perror("bind");
return 3;
}
char buf[1024];//缓冲区
//4. 服务器接收客户信息
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
ssize_t s = recvfrom(sock, buf, sizeof(buf)-1, 0,(struct sockaddr*)&client,&len);//后面两个参数是 输出型参数
if( s > 0 )//读成功
{
buf[s] = 0;
printf("[%s:%d:%s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
sendto( sock, buf, strlen(buf) , 0 , (struct sockaddr*)&client, sizeof(client));
}
}
close(sock);
return 0;
}
udp_client.c
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
if(argc != 3)
{
printf("Usage:%s ip port\n",argv[0]);
return 1;
}
//1. 创建套接字
int sock = socket(AF_INET, SOCK_DGRAM , 0 );// SOCK_DGRAM 表示UDP
if(sock < 0)
{
perror("socket");
return 2;
}
printf("sock:%d\n",sock);
//2. 命名套接字
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));//端口号是2位的数
server.sin_addr.s_addr = inet_addr(argv[1]);
//3. 客户端尽量不绑定端口号
char buf[1024];//缓冲区
//4. 客户端发送信息
while(1)
{
printf("Please Enter# ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf)-1);//-1是为了去掉‘/0’
if( s > 0 )
{
buf[s-1] = 0;
sendto( sock, buf, strlen(buf) , 0 , (struct sockaddr*)&server, sizeof(server));
ssize_t _s = recvfrom(sock,buf,sizeof(buf)-1,0,NULL,NULL);
if(_s > 0)
{
buf[_s] = 0;
printf("server echo# %s\n",buf);
}
}
}
close(sock);//最后记得关闭sock,因为文件描述符也会有文件描述符泄漏
return 0;
}
测试代码:
1. 先编译运行服务器
2. 再编译运行客户端,并向服务器发送消息
3. 服务器接收信息
4. 按ctrl+c,结束客户端进程
5. 服务器一直等待接受信息,直到又打开一个客户端,然后向服务器发送消息或者按ctrl+c将服务器的进程也结束
5. 分别按ctrl+c结束客户端进程和服务器进程
另外,我们可以在同一网段和别的ip去建立连接:
下面是TCP服务器和客户端连接的例子,但是UDP连接的方式和这个相同:
一. 先去ping 别人的ip,下面就是成功的信息:
二. 再去向别人发送客户端的可执行文件:192.168.31.209 是对方的ip地址,:/home是把可执行文件发到对方的home目录下,最底下是输入对方的密码
三. 自己去运行服务器端:
192.168.31.32是我自己的ip地址,8080是绑定的端口
./Tcp_server 192.168.31.32 8080
四. 别人运行客户端:
ip地址和端口同服务器的
./Tcp_client 192.168.31.32 8080