UDP发送方&同时接收C
我必须编写一个 C 应用程序,它既充当 UDP 发送方又充当 UDP 发送方。接收者。程序应该首先检测广播地址,然后发送消息 JOIN(名字被读取),1 次/分钟,然后是一些消息。我理解了广播包的部分。我不知道如何将我的发送者也变成接收者。 到目前为止我的代码: ---旧代码---
编辑: 我现在知道我已经解决了这个问题,无需 select() 或 poll(),而是使用 fork() ..类似于创建 2 个单独的进程,分别处理写入套接字和从套接字读取数据。我设法发送数据。我在从套接字读取数据时遇到一些问题。我收到像我发送的字符串的最后一个字符一样的东西。另外,我有一个错误“:无效参数”。我尝试过调试,但我真的不知道这个错误来自哪里。它在我执行 fork() 之后出现。我必须能够忽略我以某种方式发送的消息,但是在本地测试它很令人困惑(我必须接收来自其他人的消息,并且还必须知道向我发送消息的 IP 地址)。现在,如果我启动应用程序两次,在一个应用程序中,我不会收到来自另一个应用程序的消息,只会收到该应用程序发送的最后一个字符。 这是我的代码:
#includes..
#define MAXLEN 100
#define MAXNAME 20
#define PORT 8888
#define MAX 20
int sockfd;
struct sockaddr_in socket_in; //connector's info
char name[MAXNAME];
int numbytes;
char senders[MAX];
void sendJoin (int signal) {
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
printf("Sent %s to %s (%d bytes)\n", name,inet_ntoa(socket_in.sin_addr),numbytes);
alarm(5);
}
void leaveGroup(int signal) {
/* Broadcast LEAVE and end execution */
char msg[10];
strcpy(msg, "LEAVE\0");
if ((numbytes=sendto(sockfd, msg, strlen(msg), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendLEAVE");
exit(1);
}
printf("\nSent LEAVE message to %s (%d bytes)\n", inet_ntoa(socket_in.sin_addr),numbytes);
scanf("%s", msg);
close(sockfd);
exit(1);
}
void read_socks() {
char message[MAXLEN];
int size = sizeof(socket_in);
numbytes = recvfrom (sockfd, &message, 1, 0,
(struct sockaddr*) &socket_in, &size);
if(strcmp(message, name)!=0) {
printf("Received: %s\n", message);
}
}
int main(void){
struct hostent *hst;
int broadcast = 1;
if ((hst=gethostbyname("192.168.240.255")) == NULL) { // get the host info
perror("gethostbyname");
exit(1);
}
if((sockfd=socket(AF_INET, SOCK_DGRAM, 0))==-1) {
perror("socket");
exit(1);
}
if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))==-1){
perror("setsockopt(SO_BROADCAST)");
exit(1);
}
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
signal(SIGINT, leaveGroup);
signal(SIGALRM, sendJoin);
printf("NAME: ");
fgets(name,MAXNAME,stdin);
strcpy(name,strcat("JOIN: ", name));
name[strlen(name)-1]='\0';
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
printf("Sent %s to %s (%d bytes)\n", name,inet_ntoa(socket_in.sin_addr),numbytes);
alarm(5);
while (1)
{
int pid = fork();
if(pid==0){ //Child process reads from the socket
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
sockfd = bind(sockfd, (struct sockaddr*) &socket_in, sizeof(socket_in));
if(sockfd==-1) perror("Bind error. Port is already in use!");
read_socks();
exit(0);
}
else if(pid > 0){ //Parent process sends data through the socket
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
}
sleep(4);
}
close(sockfd);
return 0;
}
我非常感谢一些建议。
I have to write a C app that will act as both UDP sender & receiver. The program should first detect the broadcast address, then send the message JOIN (name is read), 1 time/minute, then some messages. I understood the part with broadcasting packages. I can't figure out how to turn my sender into a receiver also.
My code so far:
---old code ---
Edit:
I now know that I have solve this without select() or poll(), but with fork()..Something like creating 2 separate processes that will deal with writing to the socket and, respectively, reading data from the socket. I manage to send data. I have some troubles reading data from the socket. I receive smth like the last characters of the string I send. Also, I have an error ":Invalid argument"..I've tried debugging but I don't really know where this error comes from. It appears just after I do the fork(). I have to be able to ignore mssages that I send somehow, but testing this locally it's confusing (I have to receive messages from others and also, know the IP address that sent me the message). Now, if I start the app twice, In one app I don't receive messages from the other, just the last characters of what the app sends.
Here's my code:
#includes..
#define MAXLEN 100
#define MAXNAME 20
#define PORT 8888
#define MAX 20
int sockfd;
struct sockaddr_in socket_in; //connector's info
char name[MAXNAME];
int numbytes;
char senders[MAX];
void sendJoin (int signal) {
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
printf("Sent %s to %s (%d bytes)\n", name,inet_ntoa(socket_in.sin_addr),numbytes);
alarm(5);
}
void leaveGroup(int signal) {
/* Broadcast LEAVE and end execution */
char msg[10];
strcpy(msg, "LEAVE\0");
if ((numbytes=sendto(sockfd, msg, strlen(msg), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendLEAVE");
exit(1);
}
printf("\nSent LEAVE message to %s (%d bytes)\n", inet_ntoa(socket_in.sin_addr),numbytes);
scanf("%s", msg);
close(sockfd);
exit(1);
}
void read_socks() {
char message[MAXLEN];
int size = sizeof(socket_in);
numbytes = recvfrom (sockfd, &message, 1, 0,
(struct sockaddr*) &socket_in, &size);
if(strcmp(message, name)!=0) {
printf("Received: %s\n", message);
}
}
int main(void){
struct hostent *hst;
int broadcast = 1;
if ((hst=gethostbyname("192.168.240.255")) == NULL) { // get the host info
perror("gethostbyname");
exit(1);
}
if((sockfd=socket(AF_INET, SOCK_DGRAM, 0))==-1) {
perror("socket");
exit(1);
}
if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))==-1){
perror("setsockopt(SO_BROADCAST)");
exit(1);
}
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
signal(SIGINT, leaveGroup);
signal(SIGALRM, sendJoin);
printf("NAME: ");
fgets(name,MAXNAME,stdin);
strcpy(name,strcat("JOIN: ", name));
name[strlen(name)-1]='\0';
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
printf("Sent %s to %s (%d bytes)\n", name,inet_ntoa(socket_in.sin_addr),numbytes);
alarm(5);
while (1)
{
int pid = fork();
if(pid==0){ //Child process reads from the socket
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
sockfd = bind(sockfd, (struct sockaddr*) &socket_in, sizeof(socket_in));
if(sockfd==-1) perror("Bind error. Port is already in use!");
read_socks();
exit(0);
}
else if(pid > 0){ //Parent process sends data through the socket
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
}
sleep(4);
}
close(sockfd);
return 0;
}
I would greatly appreaciate some suggestions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要一个选择或轮询循环。 StackOverflow 上有很多与这些相关的问题。
我还建议将套接字设置为非阻塞以避免一些罕见的问题。
或者,如果您在 Windows 上编写,则可以将网络设置为使用事件。
You need a select or poll loop. There are plenty of StackOverflow questions relating to these.
I also recommend setting your sockets to non-blocking to avoid some rare problems.
Or if you are writing on Windows you can set your networking up to use events.
你需要做的是暂停你的程序,直到发生以下两种情况之一:
如果你想暂停直到发生多种情况之一,unix 上的解决方案发生的事情是函数
select()
。对于您的情况,另一个可能的解决方案是使用非阻塞 I/O 并偶尔检查新包 - 但这基本上是主动轮询,而主动轮询很糟糕,很糟糕,很糟糕。
您的代码面临的问题是您的程序在
recvfrom()
中被阻塞,直到收到消息为止。 (注意:我不完全确定您的 SIGALRM 方法是否确实应该在阻塞 I/O 等待期间工作,但我假设信号会排队直到您的读取操作完成(收到数据))What you need to do is suspend your program until one of two things happen:
The solution on unix, if you want to suspend until one of multiple things happen, is the function
select()
.Another possible solution in your case is to use non-blocking I/O and check for new packages once in a while -- but that's basically active polling and active polling is bad, bad, bad.
The problem you face with your code is that your program is blocked in
recvfrom()
until it gets a message. (Note: I'm not totally sure whether your SIGALRM method should indeed work during blocked I/O wait but I assume the signal gets queued until your reading operation is finished (data received))select(2)
、poll(2)
和相关函数可让您等待文件描述符上的事件和超时。使用这些系统调用之一时,无需使用
alarm()
。alarm()
有时用于启动带有超时的read(2)
或write(2)
调用(尽管我更喜欢使用< code>select() 即使在这种情况下,这也意味着我不关心还有谁可能在使用SIGALARM
)。当超时到期时,
poll()
和select()
都会返回0
。某些select()
实现会使用剩余时间更新timeout
参数,而其他实现则不会。在任何情况下,由于select()
或poll()
可能已提前唤醒以处理某些其他事件(或者因为它们被信号中断),因此正确的做法是所做的事情是检查超时是否确实已过期/重新计算超时,传统上使用 time(2) 或 gettimeofday(2) 完成此操作,但在现代应该更好地使用clock_gettime(2)
和CLOCK_MONOTONIC
时钟,它不受时钟调整(date(1)
、闰秒、夏令时,...)。select(2)
,poll(2)
and relatives let you wait for events on file descriptors and timeouts.When using one of these syscalls, there is no need to use
alarm()
.alarm()
is sometimes used to launch aread(2)
orwrite(2)
call with a timeout (though I prefer to useselect()
even in this case, it means I don't care who else might be usingSIGALARM
).Both
poll()
andselect()
return0
when the timeout expires. Someselect()
implementations update thetimeout
parameter with the remaining time, others don't. In any case, sinceselect()
orpoll()
may have awakened earlier for processing some other event (or because they were interrupted by a signal), the correct thing to do is checking if the timeout has really expired / recalculating the timeout, something which has traditionally been done usingtime(2)
orgettimeofday(2)
, but which in modern times should be better done usingclock_gettime(2)
with theCLOCK_MONOTONIC
clock, which is immune to clock adjustments (date(1)
, leap seconds, daylight saving time, ...).