您的位置:首页 > 理论基础 > 计算机网络

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: