linux网络编程(如何编写一个UDP通信程序)
2015-06-14 11:07
477 查看
UDP数据通讯原理
UDP数据通讯分服务端(软件)和客户端端:
服务端(软件)(服务器)先运行,服务端,不需要事先知道客户端IP和port
客户端(软件)(客户端机器)后运行,一定是客户端先给服务端发包,客户端一定先知道服务端的IP和port
UDP通信实现
1. 头文件
#include <sys/types.h>
#include <sys/socket.h>
2. 数据结构
// Internet协议地址结构
struct sockaddr{
// 地址的通信领域
unsigned short int sa_family;
// ip(4B) 和 port(2B)
char sa_data[14];
};
// 通用数据结构
struct sockaddr_in {
unsigned short int sin_family;
unsigned short int sin_port; // port
struct in_addr sin_addr; // ip地址
// 填充0 (8B)
unsigned char sin_zero[sizeof (struct sockaddr) -
(sizeof (unsigned short int)) -
sizeof (unsigned short int) -
sizeof (struct in_addr)];
};
3. 函数
服务端流程
(1) 创建套接字(创建并且打开套接字)
/*
* @param[in] domain
通信领域
* @li AF_UNIX, AF_LOCAL unix域套接字通信(本机进程间)
* @li AF_INET IPv4协议通信
* @li AF_INET6 IPv6协议通信
* @param[in] type
套接字类型
* @li SOCK_STREAM
流式套接字
* @li SOCK_DGRAM
报文套接字
* @li SOCK_RAW
网络层的协议访问
* @param[in] protocol
协议标识
* @li 0
使用默认协议
*
* @return 文件描述符
* @li -1
创建失败(错误码见errno)
*/
int socket(int domain, int type, int protocol);
(2) 绑定ip地址和port(到socket(一定一个进程创建))
/*
* @param[in] sockfd
socket
* @param[in] addr
绑定地址(ip地址和port)
* @param[in] addrlen
addr的字节数
* @return @li 0
绑定成功
* @li -1
创建失败(错误码见errno)
*/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
(3) 接收数据包
/*
* @param[in] sockfd
socket
* @param[out] buf
接收数据包的buf
* @param[in] len
buf的字节数
* @param[in] flags
0
* @param[out] src_addr
源地址(IP和Port)
* @NULL
不接收源地址,此时addrlen也必须为NULL
* @param[in | out] addrlen(输入)
src_addr缓冲区字节数
* addrlen(输出)
实际地址大小
* @return @li >= 0
实际接收的字节数
* @li -1
创建失败(错误码见errno)
*/
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
(4) 发送数据包
/*
* @param[in] sockfd
socket
* @param[out] buf
发送数据包的buf
* @param[in] len
发送数据的字节数
* @param[in] flags
0
* @param[out] dest_addr
目标地址(IP和Port)
* @param[in] addrlen
dest_addr字节数
* @return @li >= 0
实际发送的字节数
* @li -1
发送失败(错误码见errno)
*/
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
(5) 关闭socket
int close(int sockfd);
客户端流程
(1) 创建套接字(创建并且打开套接字)
(2) 发送数据包
(3) 接收数据包
(4) 关闭socket
/*
* 实现目标:
* udp客户端
*
* 实现步骤:
* 1. socket
* 2. 获取用户输入
* 3. sendto用户输入的内容
* 4. recvfrom服务器发送过来的内容,并显示
* 5. close
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <strings.h>
// net
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// ./client 192.168.0.249 8888
int main(int argc, const char *argv[])
{
int ret = 0;
int sockfd;
char packet[1024];
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
socklen_t addrlen = sizeof(peer_addr);
if (argc < 3){
fprintf(stderr, "Usage: %s <server ip> <server port>\n", argv[0]);
exit(EXIT_FAILURE);
}
// 1. socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd){
perror("Fail to socket.");
exit(EXIT_FAILURE);
}
// 填充地址结构
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
while (1){
// 2. 获取用户输入
putchar('>');
fgets(packet, sizeof(packet), stdin);
packet[strlen(packet) - 1] = '\0';
// 3. sendto用户输入的内容
ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret){
perror("Fail to sendto");
break;
}
// 4. recvfrom服务器发送过来的内容,并显示
ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);
if (-1 == ret){
perror("Fail to recvfrom.");
break;
}
packet[ret] = '\0';
printf("recv : %s\n", packet);
if (strcmp(packet, "bye") == 0) break;
}
// 5. close
close(sockfd);
return 0;
}
/*
* 实现目标:
* udp服务端
*
* 实现步骤:
* 1. socket
* 2. bind
* 3. recvfrom客户发送的内容
* 4. sendto相同的内容客户端
* 5. close
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// bzero
#include <strings.h>
// net
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// ./server 192.168.0.249 8888
int main(int argc, const char *argv[])
{
int ret = 0;
int sockfd;
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
socklen_t addr_len = sizeof(peer_addr);
char packet[1024];
if (argc < 3){
fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
exit(EXIT_FAILURE);
}
// 1. socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd){
perror("Fail to socket.");
exit(EXIT_FAILURE);
}
// 2. bind
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
if (-1 == ret){
perror("Fail to bind.");
exit(EXIT_FAILURE);
}
while (1) {
// 3. recvfrom客户发送的内容
ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addr_len);
if (-1 == ret){
perror("Fail to recvfrom.");
break;
}
packet[ret] = '\0';
printf("----------------------------------------\n");
printf("ip : %s\n", inet_ntoa(peer_addr.sin_addr));
printf("port : %d\n", ntohs(peer_addr.sin_port));
printf("recv : %s\n", packet);
printf("----------------------------------------\n");
// 4. sendto相同的内容客户端
ret = sendto(sockfd, packet, ret, 0, (struct sockaddr *)&peer_addr, sizeof(struct sockaddr));
if (-1 == ret){
perror("Fail to sendto.");
break;
}
if (strcmp(packet, "bye") == 0) break;
}
// 5. close
close(sockfd);
return 0;
}
UDP数据通讯分服务端(软件)和客户端端:
服务端(软件)(服务器)先运行,服务端,不需要事先知道客户端IP和port
客户端(软件)(客户端机器)后运行,一定是客户端先给服务端发包,客户端一定先知道服务端的IP和port
UDP通信实现
1. 头文件
#include <sys/types.h>
#include <sys/socket.h>
2. 数据结构
// Internet协议地址结构
struct sockaddr{
// 地址的通信领域
unsigned short int sa_family;
// ip(4B) 和 port(2B)
char sa_data[14];
};
// 通用数据结构
struct sockaddr_in {
unsigned short int sin_family;
unsigned short int sin_port; // port
struct in_addr sin_addr; // ip地址
// 填充0 (8B)
unsigned char sin_zero[sizeof (struct sockaddr) -
(sizeof (unsigned short int)) -
sizeof (unsigned short int) -
sizeof (struct in_addr)];
};
3. 函数
服务端流程
(1) 创建套接字(创建并且打开套接字)
/*
* @param[in] domain
通信领域
* @li AF_UNIX, AF_LOCAL unix域套接字通信(本机进程间)
* @li AF_INET IPv4协议通信
* @li AF_INET6 IPv6协议通信
* @param[in] type
套接字类型
* @li SOCK_STREAM
流式套接字
* @li SOCK_DGRAM
报文套接字
* @li SOCK_RAW
网络层的协议访问
* @param[in] protocol
协议标识
* @li 0
使用默认协议
*
* @return 文件描述符
* @li -1
创建失败(错误码见errno)
*/
int socket(int domain, int type, int protocol);
(2) 绑定ip地址和port(到socket(一定一个进程创建))
/*
* @param[in] sockfd
socket
* @param[in] addr
绑定地址(ip地址和port)
* @param[in] addrlen
addr的字节数
* @return @li 0
绑定成功
* @li -1
创建失败(错误码见errno)
*/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
(3) 接收数据包
/*
* @param[in] sockfd
socket
* @param[out] buf
接收数据包的buf
* @param[in] len
buf的字节数
* @param[in] flags
0
* @param[out] src_addr
源地址(IP和Port)
* @NULL
不接收源地址,此时addrlen也必须为NULL
* @param[in | out] addrlen(输入)
src_addr缓冲区字节数
* addrlen(输出)
实际地址大小
* @return @li >= 0
实际接收的字节数
* @li -1
创建失败(错误码见errno)
*/
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
(4) 发送数据包
/*
* @param[in] sockfd
socket
* @param[out] buf
发送数据包的buf
* @param[in] len
发送数据的字节数
* @param[in] flags
0
* @param[out] dest_addr
目标地址(IP和Port)
* @param[in] addrlen
dest_addr字节数
* @return @li >= 0
实际发送的字节数
* @li -1
发送失败(错误码见errno)
*/
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
(5) 关闭socket
int close(int sockfd);
客户端流程
(1) 创建套接字(创建并且打开套接字)
(2) 发送数据包
(3) 接收数据包
(4) 关闭socket
/*
* 实现目标:
* udp客户端
*
* 实现步骤:
* 1. socket
* 2. 获取用户输入
* 3. sendto用户输入的内容
* 4. recvfrom服务器发送过来的内容,并显示
* 5. close
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <strings.h>
// net
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// ./client 192.168.0.249 8888
int main(int argc, const char *argv[])
{
int ret = 0;
int sockfd;
char packet[1024];
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
socklen_t addrlen = sizeof(peer_addr);
if (argc < 3){
fprintf(stderr, "Usage: %s <server ip> <server port>\n", argv[0]);
exit(EXIT_FAILURE);
}
// 1. socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd){
perror("Fail to socket.");
exit(EXIT_FAILURE);
}
// 填充地址结构
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
while (1){
// 2. 获取用户输入
putchar('>');
fgets(packet, sizeof(packet), stdin);
packet[strlen(packet) - 1] = '\0';
// 3. sendto用户输入的内容
ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret){
perror("Fail to sendto");
break;
}
// 4. recvfrom服务器发送过来的内容,并显示
ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);
if (-1 == ret){
perror("Fail to recvfrom.");
break;
}
packet[ret] = '\0';
printf("recv : %s\n", packet);
if (strcmp(packet, "bye") == 0) break;
}
// 5. close
close(sockfd);
return 0;
}
/*
* 实现目标:
* udp服务端
*
* 实现步骤:
* 1. socket
* 2. bind
* 3. recvfrom客户发送的内容
* 4. sendto相同的内容客户端
* 5. close
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// bzero
#include <strings.h>
// net
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// ./server 192.168.0.249 8888
int main(int argc, const char *argv[])
{
int ret = 0;
int sockfd;
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
socklen_t addr_len = sizeof(peer_addr);
char packet[1024];
if (argc < 3){
fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
exit(EXIT_FAILURE);
}
// 1. socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd){
perror("Fail to socket.");
exit(EXIT_FAILURE);
}
// 2. bind
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
if (-1 == ret){
perror("Fail to bind.");
exit(EXIT_FAILURE);
}
while (1) {
// 3. recvfrom客户发送的内容
ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addr_len);
if (-1 == ret){
perror("Fail to recvfrom.");
break;
}
packet[ret] = '\0';
printf("----------------------------------------\n");
printf("ip : %s\n", inet_ntoa(peer_addr.sin_addr));
printf("port : %d\n", ntohs(peer_addr.sin_port));
printf("recv : %s\n", packet);
printf("----------------------------------------\n");
// 4. sendto相同的内容客户端
ret = sendto(sockfd, packet, ret, 0, (struct sockaddr *)&peer_addr, sizeof(struct sockaddr));
if (-1 == ret){
perror("Fail to sendto.");
break;
}
if (strcmp(packet, "bye") == 0) break;
}
// 5. close
close(sockfd);
return 0;
}
相关文章推荐
- windows 8 设置hyper-v网络设置
- 一起学习CC3200系列教程之2个TCP_非阻塞及阻塞设置
- 计算机网络--物理层 的一点总结
- ARM硬件平台上基于UCOS移植Lwip网络协议栈
- ARM硬件平台上基于UCOS移植Lwip网络协议栈
- ARM硬件平台上基于UCOS移植Lwip网络协议栈 分类: 嵌入式开发学习 2015-06-14 10:33 55人阅读 评论(1) 收藏
- unity开发:Qt C++与unity之间TCP网络通信
- 网络传输
- BZOJ 3391: [Usaco2004 Dec]Tree Cutting网络破坏( dfs )
- TCP/IP详解_网际协议IP(二)_IP数据报格式
- TCP 报文
- 关于DNS DHCP FTP TFTP HTTP WEB
- TCP/IP 11种状态变迁
- 使用TCP协议写一个可以上传文件的服务器和客户端
- Linux网络设备驱动-- skb
- HDU--杭电--2732//POJ--2711--Leapin' Lizards--网络流
- Wireshark过滤规则之:IP数据包过滤
- 基于MFC的网络浏览器Demo
- android 网络传输中UDP和TCP传输
- Qt开发:TCP和UDP网络通信