我是网络通信主题的新手,但是想建立一个UDP服务器客户端连接,一个参与者不断地广播数据是否有人正在收听,两个参与者开始接收和存储这些信息只要他们准备好这样做(如果他们错过了那之前发送的内容,那就没问题)。这个想法是除了一个参与者发送数据(发射和遗忘)和两个接收它们的参与者之外没有其他通信,没有任何形式的反馈给发送部分。现在我想让它在我的本地主机上运行,但是想在网络上使用它。
我一直在寻找一个解决方案已经有一段时间了,并且决定让客户端在两个独立的端口上连续广播文件流,这样接收的两个服务器可以分别绑定到一个端口而不会相互阻塞(如果有更好的方法,我愿意接受建议)。
到目前为止,我已经能够按照these指令与一个客户端和一个服务器建立这种通信。但是,当我尝试在客户端可执行文件中设置第二个套接字时,一旦到达sendto()部分,我总是会收到错误消息 无效参数 。
因为我自己找不到解决方案,但我想请求一些帮助。
到目前为止我的代码包含了 客户:
/** set up socket_1 properties */
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
/** Read address information of incoming connection */
int status;
struct addrinfo *servinfo;
if ((status = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd;
struct addrinfo *p;
for ( p = servinfo; p != NULL; p = p->ai_next ) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 1: %s.\n", strerror(errno) );
return 2;
}
/** set up socket_2 */
// ( reuse socket_1 hints and change the port number )
/** Read address information of incoming connection */
int status_2;
struct addrinfo *servinfo_2;
if ((status_2 = getaddrinfo(NULL, MYPORT_2, &hints, &servinfo_2)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status_2));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd_2;
struct addrinfo *p_2;
for ( p_2 = servinfo_2; p_2 != NULL; p_2 = p_2->ai_next ) {
if ((sockfd_2 = socket(p_2->ai_family, p_2->ai_socktype, p_2->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p_2 == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 2: %s.\n", strerror(errno) );
return 2;
}
...
some file read/write related stuff
...
while ( /* some condition */ )
{
if ( ( readBytes = pread( fd, buf, BUFFER_SIZE, offset ) ) == -1 ){
printf("[ERROR]: %s.\n", strerror(errno) );
free( buf );
close( fd );
close( sockfd );
exit(1);
}
// the next line is generating the error message
if ( ( numbytes = sendto( sockfd, buf, readBytes, 0, p->ai_addr, p->ai_addrlen ) ) == -1 )
{
perror("sender_1: sendo.\n");
free( buf );
close( fd );
close( sockfd );
exit(1);
}
if ( ( numbytes = sendto( sockfd_2, buf, readBytes, 0, p_2->ai_addr, p_2->ai_addrlen ) ) == -1 )
{
perror("sender_2: sendo.\n");
free( buf );
close( fd );
close( sockfd_2 );
exit(1);
}
}
.
.
.
free( buf );
freeaddrinfo(servinfo);
freeaddrinfo(servinfo_2);
printf( "Broadcasting complete.\n" );
/** Clean what is not necessary anymore */
close( fd );
close( sockfd );
return 0;
}
我尝试添加重用端口和IP功能,以确保没有任何阻止新套接字的设置,但这并没有解决我的问题
我的服务器端似乎工作正常,但以防万一我也会在这里发布:
int main(int argc, char **argv)
{
if (argc < 2){
printf("Please provide image Name ID.\n");
exit(1);
}
struct addrinfo hints;
struct addrinfo *servinfo = NULL; // will point to getaddrinfo() results
memset(&hints, 0, sizeof hints); // make sure struct is empty
hints.ai_family = AF_UNSPEC; // don't care if IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // Use UDP protocol
hints.ai_flags = AI_PASSIVE;
int res;
if ((res = getaddrinfo( NULL, argv[1]/* SERVERPORT*/, &hints, &servinfo )) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(res));
return 1;
}
/** Get socket file descriptor */
int sockfd;
struct addrinfo *p = NULL;
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
/** Allow the reuse of an IP */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Allow the reuse of a socket */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Bind found socket to desired port */
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
printf("[ERROR]: Failed to bind socket to desired port: %s.\n", strerror( errno ) );
continue;
}
break;
}
struct timeval read_timeout;
read_timeout.tv_sec = 30;
read_timeout.tv_usec = 500;
if ( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof read_timeout) < 0 ){
printf( "[ERROR]: %s.\n", strerror(errno) );
}
...
some file read/write stuff
...
while ( ( numbytes = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&their_addr, &addr_len ) ) != -1)
{
.
.
.
}
printf("Done broadcasting.\n");
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
如果有人能给我一些帮助或者指出正确的方向寻找解决方案,我将不胜感激。
祝你好运