我试图在两个电台(A和B)之间建立通信。 A应该向B发送多个数据(反之亦然):"多个数据"意味着我想在一个接受会话中使用来自两个站的发送和 recv 。目前,我只是尝试每个连接发送超过1个数据包。由于我不熟悉处理套接字,我很难理解套接字背后的概念。在下面的代码中,接收器成功检索发送的第一个 int 发送器,但不是以下代码。你能告诉我我做错了吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#define DATA_TO_SEND_LENGTH 9
#define PRINT_ERRNO_EXIT(who,id) { \
int verrno=errno; \
printf("%s ERRNO: %d\nexit id: %d\n",who==0?"sender":"receiver",verrno,id); \
return id; \
}
int main(){
char* ipaddress="127.0.0.1";
int portNumber=12345;
int socketOptionalValue=1;
const int dataToSend[]={1,2,3,4,5,6,7,8,9};
if (fork()==0){
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@ CHILD: HE IS THE SENDER @@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int socketSenderDescriptor;
struct sockaddr_in destinationInfos;
struct sockaddr_in tmp;
int i;
// ************** CREATE AND OPEN THE SOCKET *****************
inet_aton(ipaddress,&tmp.sin_addr);
socketSenderDescriptor = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor
if (socketSenderDescriptor < 0 ){
PRINT_ERRNO_EXIT(0,1);
}
if (setsockopt(socketSenderDescriptor,SOL_SOCKET,SO_REUSEADDR,&socketOptionalValue,sizeof(socketOptionalValue))!=0){
PRINT_ERRNO_EXIT(0,2);
}
if (setsockopt(socketSenderDescriptor,SOL_SOCKET,SO_KEEPALIVE,&socketOptionalValue,sizeof(socketOptionalValue))!=0){
PRINT_ERRNO_EXIT(0,2);
}
memset(&destinationInfos,0,sizeof(destinationInfos)); //clean the structure used to store destination information
destinationInfos.sin_family=AF_INET; //we want to use inet class
destinationInfos.sin_addr.s_addr=tmp.sin_addr.s_addr;//Set destination IP
destinationInfos.sin_port=htons(portNumber); //communiction port number
//connection
if (connect(socketSenderDescriptor,(struct sockaddr *)&(destinationInfos),sizeof(destinationInfos)) < 0){
PRINT_ERRNO_EXIT(0,3);
}
// ******************* SEND DATA **********************
sleep(1); //wait for the parent to start listening...
for (i=0;i<DATA_TO_SEND_LENGTH;i++){
printf("sender: i'm sending %d\n",dataToSend[i]);
send(socketSenderDescriptor,&(dataToSend[i]),sizeof(dataToSend[i]),0);
sleep(1);
}
// ******************* CLOSE SOCKET *******************
if (close(socketSenderDescriptor)!=0){
PRINT_ERRNO_EXIT(0,4);
}
printf("SENDER FINISH!\n");
return EXIT_SUCCESS;
}else {
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@ PARENT: HE IS THE RECEIVER @@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
struct sockaddr_in remoteSocketInfos;
struct sockaddr_in localSocketInfos;
int localSocketDescriptor;
int sessionSocket;
int valueReceived;
int i=0;
static socklen_t socksize=sizeof(struct sockaddr_in);
// ******************* CREATE AND BIND THE SOCKET ******************
//write inside localSocketInfos the information about our server
memset(&localSocketInfos,0,sizeof(localSocketInfos));
localSocketInfos.sin_family=AF_INET;
localSocketInfos.sin_addr.s_addr=htonl(INADDR_ANY);
localSocketInfos.sin_port= htons(portNumber);
//create the main socket where all connection to our server will be received
localSocketDescriptor=socket(AF_INET,SOCK_STREAM,0);
if (localSocketDescriptor<0){
PRINT_ERRNO_EXIT(1,1);
}
//On Linux, SO_REUSEADDR allows you to bind to an address unless an active connection is present
//see https://stackoverflow.com/questions/4979425/difference-between-address-in-use-with-bind-in-windows-and-on-linux-errno
setsockopt(localSocketDescriptor,SOL_SOCKET,SO_REUSEADDR,&socketOptionalValue,sizeof(socketOptionalValue));
//Bind our socket to the socketDescription: this allows the machine to know the data
//received on the port specified in the sockaddr_in should be handled by our specified socket.
if (bind(localSocketDescriptor,(struct sockaddr*)&localSocketInfos,sizeof(struct sockaddr))!=0){
PRINT_ERRNO_EXIT(1,2);
}
//tells our program to start listening the socket we have created. This will NOT block the flow of the program because
//we are not waiting anything at all.
if (listen(localSocketDescriptor,10)!=0){
PRINT_ERRNO_EXIT(1,3);
}
// ************************ WAIT FOR CONNECTIONS ********************
do {
i++;
printf("Waiting transmission on %s, port %d...\n",inet_ntoa(localSocketInfos.sin_addr),localSocketInfos.sin_port);
sessionSocket=accept(localSocketDescriptor,(struct sockaddr*)&remoteSocketInfos,&socksize);
if (sessionSocket<0){
int verrno=errno;
printf("receiver ERRNO: %d\n",verrno);
continue;
}
printf("Incoming transmission from %s, port %d...\n",inet_ntoa(remoteSocketInfos.sin_addr),remoteSocketInfos.sin_port);
recv(sessionSocket,&valueReceived,sizeof(valueReceived),0);
printf("DATA READ! %d\n",valueReceived);
close(sessionSocket);
} while(i<DATA_TO_SEND_LENGTH);
if (close(localSocketDescriptor)==0){
PRINT_ERRNO_EXIT(1,4);
}
printf("RECEIVER FINISH!\n");
return EXIT_SUCCESS;
}
}
我也发布了我的程序输出,希望它可以帮助你找到我做错的事情:
Waiting transmission on 0.0.0.0, port 14640...
Incoming transmission from 127.0.0.1, port 63718...
sender: i'm sending 1
DATA READ! 1
Waiting transmission on 0.0.0.0, port 14640...
sender: i'm sending 2
sender: i'm sending 3
sender: i'm sending 4
sender: i'm sending 5
sender: i'm sending 6
sender: i'm sending 7
sender: i'm sending 8
sender: i'm sending 9
SENDER FINISH!
答案 0 :(得分:1)
在接收者流程中,accept()
只需要调用一次。由于您将accept()
置于while
循环内,因此在accept
上将阻止循环的第二次迭代,因为没有新连接进入。
一个简单的解决方法是将accept
放在循环之外。您可以尝试以下修复程序,看看它是否有效。请注意,循环后也会移动close
。
// ************************ WAIT FOR CONNECTIONS ********************
printf("Waiting transmission on %s, port %d...\n",inet_ntoa(localSocketInfos.sin_addr),localSocketInfos.sin_port);
sessionSocket=accept(localSocketDescriptor,(struct sockaddr*)&remoteSocketInfos,&socksize);
if (sessionSocket<0){
int verrno=errno;
printf("receiver ERRNO: %d\n",verrno);
PRINT_ERRNO_EXIT(1,5);
}
do {
i++;
printf("Incoming transmission from %s, port %d...\n",inet_ntoa(remoteSocketInfos.sin_addr),remoteSocketInfos.sin_port);
recv(sessionSocket,&valueReceived,sizeof(valueReceived),0);
printf("DATA READ! %d\n",valueReceived);
} while(i<DATA_TO_SEND_LENGTH);
close(sessionSocket);