144 lines
3.7 KiB
C
144 lines
3.7 KiB
C
|
#include <stdio.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
#include <pthread.h>
|
||
|
#include <stdlib.h> // atoi
|
||
|
|
||
|
void *recv_task(void *arg); // 接收数据的线程任务函数
|
||
|
void *send_task(void *arg); // 发送数据的线程任务函数
|
||
|
|
||
|
int main(int argc, char const *argv[])
|
||
|
{
|
||
|
if (argc != 2)
|
||
|
{
|
||
|
printf("usage: %s port\n", argv[0]);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
|
if (sfd < 0)
|
||
|
{
|
||
|
perror("socket");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// 绑定 ip 和端口号 (开启 UDP 服务)
|
||
|
struct sockaddr_in bind_addr;
|
||
|
bzero(&bind_addr, sizeof(bind_addr));
|
||
|
bind_addr.sin_family = AF_INET;
|
||
|
bind_addr.sin_port = htons(atoi(argv[1]));
|
||
|
bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 主机 ip 中的任意一个都可以使用
|
||
|
|
||
|
if (bind(sfd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0)
|
||
|
{
|
||
|
perror("bind");
|
||
|
close(sfd);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
pthread_t t1, t2;
|
||
|
pthread_create(&t1, NULL, recv_task, (void *)&sfd);
|
||
|
pthread_create(&t2, NULL, send_task, &sfd);
|
||
|
|
||
|
pthread_join(t2, NULL);
|
||
|
pthread_cancel(t1); // 发完后,取消接收
|
||
|
pthread_join(t1, NULL); // 等待接收线程结束
|
||
|
|
||
|
close(sfd);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void *recv_task(void *arg)
|
||
|
{
|
||
|
int sock_fd = *((int *)arg); // 取出传入的 socket 描述符
|
||
|
printf("启动recv_task %d\n", sock_fd);
|
||
|
char buf[128] = "";
|
||
|
struct sockaddr_in src_addr; // 发送数据的源地址
|
||
|
socklen_t sock_len; // 原地址 socket 的长度
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
bzero(buf, sizeof(buf));
|
||
|
bzero(&src_addr, sizeof(src_addr));
|
||
|
|
||
|
ssize_t len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &sock_len);
|
||
|
if (len < 0)
|
||
|
{
|
||
|
perror("recvfrom");
|
||
|
}
|
||
|
|
||
|
char ip[INET_ADDRSTRLEN] = "";
|
||
|
int port = ntohs(src_addr.sin_port);
|
||
|
inet_ntop(AF_INET, &src_addr.sin_addr.s_addr, ip, INET_ADDRSTRLEN);
|
||
|
|
||
|
printf("%s:%d 说: %s\n", ip, port, buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void *send_task(void *arg)
|
||
|
{
|
||
|
int sock_fd = *((int *)arg);
|
||
|
// @192.168.1.2:8000
|
||
|
// hi,hello
|
||
|
// good,disen
|
||
|
// haha
|
||
|
// yes
|
||
|
// @:8500
|
||
|
// very,good
|
||
|
|
||
|
char ip[INET_ADDRSTRLEN] = "";
|
||
|
int port = 0;
|
||
|
struct sockaddr_in dst_addr; // 目标地址
|
||
|
while (1)
|
||
|
{
|
||
|
char buf[128] = "";
|
||
|
fgets(buf, sizeof(buf), stdin);
|
||
|
buf[strlen(buf) - 1] = 0; // 去掉最后的换行
|
||
|
|
||
|
if (buf[0] == '@')
|
||
|
{
|
||
|
if (buf[1] == ':')
|
||
|
{
|
||
|
strcpy(ip, "127.0.0.1");
|
||
|
port = atoi(buf + 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strcpy(ip, strtok(buf + 1, ":"));
|
||
|
port = atoi(strtok(NULL, ":"));
|
||
|
}
|
||
|
|
||
|
printf("ip:port is %s:%d\n",ip,port);
|
||
|
// 重置
|
||
|
bzero(&dst_addr, sizeof(dst_addr));
|
||
|
dst_addr.sin_family = AF_INET;
|
||
|
dst_addr.sin_port = htons(port);
|
||
|
// inet_pton(AF_INET, ip, &dst_addr.sin_addr.s_addr); // 按ipv4转地址
|
||
|
dst_addr.sin_addr.s_addr = inet_addr(ip);
|
||
|
// inet_pton(sock_fd, ip, &dst_addr.sin_addr.s_addr); // bug地方
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (strncmp(buf, "exit", 4) == 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (port == 0)
|
||
|
{
|
||
|
printf("请先确认发送的目的ip和端口号\n");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// 发送数据
|
||
|
if (sendto(sock_fd, buf, strlen(buf), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) < 0)
|
||
|
{
|
||
|
perror("sendto");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|