Same socket for sending and receivng?

Started by
7 comments, last by hplus0603 19 years, 6 months ago
Ive read 'Beej's Networking Tutorials' just like the FAQ tells me too. And i tried to change the UDP talker-lister programm a bit, so the listener would sent an acknowledgement packet. But I can't use the socket with wich i send data to receive data aswell. What i do is this: sockfd=socket(AF_INET, SOCK_DGRAM, 0); bind(sockfd,...); sendto(sockfd, message,...); recvfrom(sockfd,buf,...); recvfrom then gives an error: "recvfrom: No Error" (perror("recvfrom");) So do i need another socket for receiving, or am i just being stupid? I use Visual C++ and <winsock.h> Thanks for reading this
Advertisement
In UDP, you can send and receive on the same socket.

However, if the socket is non-blocking, then calling recvfrom() will immediately return, even if there is no data.

Also, if you run two copies of the same program on the same machine, they can't both bind to the same port -- don't know if this is your problem or not -- it doesn't even really say what the actual error would be (your detection/printing code isn't part of the pasted code).
enum Bool { True, False, FileNotFound };
well this is the source that i use. I copied it from the tutorial and changed it a bit for Visual C++. And the two programs worked. Then i just added Bind() and Recvfrom() to be able to send with the socket aswell.Its a regular blocking socket. If you compile it ull see what the problem is.

#define THEIRPORT 4950    // the port users will be connecting to#define MYPORT 4949#include <winsock.h>#include <iostream.h>#define MAXBUFLEN 100int main()    {		WSAData wsaData;//		WSAStartup(MAKEWORD(2, 2), &wsaData);		char buf[MAXBUFLEN];        int sockfd;        struct sockaddr_in their_addr,my_addr; // connector's address information        struct hostent *he;        int numbytes;		char message[100];		cin >> message;		my_addr.sin_family = AF_INET;         // host byte order        my_addr.sin_port = htons(MYPORT);     // short, network byte order        my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP        memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct		if ((he=gethostbyname("Ramon")) == NULL) {  // get the host info            perror("gethostbyname");			cout << "Coulnt find host";			char chr[10];			cin >> chr;            exit(1);		}		their_addr.sin_family = AF_INET;     // host byte order        their_addr.sin_port = htons(THEIRPORT); // short, network byte order        their_addr.sin_addr = *((struct in_addr *)he->h_addr);        memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct		        if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {            perror("socket");			cout << "Socket error";			char chr[10];			cin >> chr;            exit(1);        }		if (bind(sockfd, (struct sockaddr *)&my_addr,                                              sizeof(struct sockaddr)) == -1) {            perror("bind");			char chr[10];			cin >> chr;            exit(1);        }        if ((numbytes=sendto(sockfd, message, strlen(message), 0,            (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1) {            perror("sendto");            exit(1);        }        cout << numbytes <<" bytes where send to "			<< inet_ntoa(their_addr.sin_addr) <<endl;		int addr_len = sizeof(struct sockaddr);		if ((numbytes=recvfrom(sockfd,buf, MAXBUFLEN-1, 0,			(struct sockaddr *)&their_addr,&addr_len)) == -1) {            perror("recvfrom");				char chr[10];	    cin >> chr;            exit(1);//and this is where the programm stops        }		cout << numbytes << " received" << endl;		cout << buf << endl;                                                       closesocket(sockfd);	char chr[10];	cin >> chr;        return 0;   }
yay i fixed it. The problem was that the packet, that i send first, needs to be received, by the other programm, before i can recv a packet with the same socket. So i just added Sleep(100); and it works :)
Thanks anyway hplus0603!
Quote:Original post by xIshtarx
yay i fixed it. The problem was that the packet, that i send first, needs to be received, by the other programm, before i can recv a packet with the same socket. So i just added Sleep(100); and it works :)


Although this might smell like a nice fix right now, this isn't a good way to go about doing things. What if you are experiencing lag, and it takes more than 100ms for the packet to get back to you? Or what if another packet gets there ahead of the one you're expecting?

For your example, waiting is sufficient. Just keep these pitfalls in mind for when you write your next project. ;)
Thanks for the feedback.
It's my first networking programm, just to learn how UDP works. Btw if i want it non-blocking, i just use this?:
fcntl(sockfd, F_SETFL, O_NONBLOCK);
I dunno it it works for UDP aswell and that tutorial said:

Generally speaking, however, this type of polling is a bad idea. If you put your program in a busy-wait looking for data on the socket, you'll suck up CPU time like it was going out of style. A more elegant solution for checking to see if there's data waiting to be read comes in the following section on select().

I dont understand, why it would suck up CPU time. Can u use select on udp sockets aswell?
It would suck up CPU time because if your socket is nonblocking, you'd just write a while() loop, looping while the return value is WSAEWOULDBLOCK, something like this:
do {   int nRet = recv(...);} while((nRet == -1) && (WSAGetLastError() == WSAEWOULDBLOCK));


select() allows your thread to sleep until a a message arrives.
Yes, you can use select() on UDP sockets.
Do i really need to use threads? or can i just do something like this?

while(true){
Recv();
Send();
UpdateGame();
RenderGame();
}
Becus currently my game sucks up all the CPU time anyway :)
Could u point me some tutorials about multithreading (for networking)?
xIshtarx,

You don't need to use threads. In fact, the FAQ suggests that threads seldom help with networking games, and often hurt a bit.

The loop you suggest will work fine for a simple networked game, using non-blocking sockets. Once you get a little more fancy, you probably want to update physics on a fixed time-step basis, but keep the rest of the loop the same (including animation, which can run separate from physics).
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement