Go to Post I got to meet Andy Baker, and Grady, and I saw Andy Brockway. Is that like an Andy Triple Play or something?? ;) - Ian Curtis [more]
Home
Go Back   Chief Delphi > Technical > Programming
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Closed Thread
Thread Tools Rating: Thread Rating: 2 votes, 5.00 average. Display Modes
  #1   Spotlight this post!  
Unread 07-02-2015, 21:11
pensono pensono is offline
Registered User
FRC #5495
 
Join Date: Jan 2015
Location: Snohomish, WA
Posts: 15
pensono is an unknown quantity at this point
Using the "Team Use" TCP ports

FRC allows the use of TCP ports 5800-5810 for our team use. I would like to use them to send arbitrary data from my driver station laptop, to the roboRIO. This may sound trivial at first, write a TCP client on the driver station, write a server on the roboRIO, and start sending data.

There is a problem with this though:
The address of the roboRIO is determined by DCHP. This makes it impossible to know for sure what address to connect to from the laptop. I think the driver station software gets around this by using mDNS, but there's no support for mDNS in something like winsock.

Along with this, I can't find anywhere in the documentation how to run code asynchronously, which is required for blocking network code.

I also can't find any WPI support for networking, although there seems to be some standard Linux networking that works.

Here is my code on both ends, both are taken almost entirely from examples:

Client:
Code:
#define WIN32_LEAN_AND_MEAN

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <string>

// link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define DEFAULT_PORT "5805" 
#define DEFAULT_BUFFER_LENGTH	512

class Remote {
public:
	Remote(char* servername)
	{
		szServerName = servername;
		ConnectSocket = INVALID_SOCKET;
	}

	bool Start() {
		WSADATA wsaData;

		// Initialize Winsock
		int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
		if (iResult != 0)
		{
			printf("WSAStartup failed: %d\n", iResult);
			return false;
		}

		printf("WSA Started up\n");
		struct addrinfo	*result = NULL,
			*ptr = NULL,
			hints;

		ZeroMemory(&hints, sizeof(hints));
		hints.ai_family = AF_UNSPEC;
		hints.ai_socktype = SOCK_STREAM;
		hints.ai_protocol = IPPROTO_TCP;

		// Resolve the server address and port
		iResult = getaddrinfo(szServerName, DEFAULT_PORT, &hints, &result);
		if (iResult != 0)
		{
			printf("getaddrinfo failed: %d\n", iResult);
			WSACleanup();
			return false;
		}

		printf("Got the address...\n");

		ptr = result;

		// Create a SOCKET for connecting to server
		ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

		if (ConnectSocket == INVALID_SOCKET)
		{
			printf("Error at socket(): %d\n", WSAGetLastError());
			freeaddrinfo(result);
			WSACleanup();
			return false;
		}
		printf("Made a socket\n");

		// Connect to server
		iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);

		if (iResult == SOCKET_ERROR)
		{
			closesocket(ConnectSocket);
			ConnectSocket = INVALID_SOCKET;
		}


		freeaddrinfo(result);

		if (ConnectSocket == INVALID_SOCKET)
		{
			printf("Unable to connect to server!\n");
			WSACleanup();
			return false;
		}

		printf("Connected to the server\n");

		return true;
	};

	// Free the resouces
	void Stop() {
		int iResult = shutdown(ConnectSocket, SD_SEND);

		if (iResult == SOCKET_ERROR)
		{
			printf("shutdown failed: %d\n", WSAGetLastError());
		}

		closesocket(ConnectSocket);
		WSACleanup();
	};

	// Send message to server
	bool Send(char* szMsg)
	{

		int iResult = send(ConnectSocket, szMsg, strlen(szMsg), 0);

		if (iResult == SOCKET_ERROR)
		{
			printf("send failed: %d\n", WSAGetLastError());
			Stop();
			return false;
		}

		return true;
	};

	// Receive message from server
	bool Recv()
	{
		char recvbuf[DEFAULT_BUFFER_LENGTH];
		int iResult = recv(ConnectSocket, recvbuf, DEFAULT_BUFFER_LENGTH, 0);

		if (iResult > 0)
		{
			char msg[DEFAULT_BUFFER_LENGTH];
			memset(&msg, 0, sizeof(msg));
			strncpy(msg, recvbuf, iResult);

			printf("Received: %s\n", msg);

			return true;
		}


		return false;
	}

private:
	char* szServerName;
	SOCKET ConnectSocket;
};
Server:
Code:
#define MAX_SIZE 50

	// Two socket descriptors which are just integer numbers used to access a socket
	int sock_descriptor, conn_desc;

	// Two socket address structures - One for the server itself and the other for client
	struct sockaddr_in serv_addr, client_addr;

	// Buffer to store data read from client
	char buff[MAX_SIZE];

	// Create socket of domain - Internet (IP) address, type - Stream based (TCP) and protocol unspecified
	// since it is only useful when underlying stack allows more than one protocol and we are choosing one.
	// 0 means choose the default protocol.
	sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);

	// A valid descriptor is always a positive value
	if (sock_descriptor < 0)
		printf("Failed creating socket\n");

	// Initialize the server address struct to zero
	bzero((char *) &serv_addr, sizeof(serv_addr));

	// Fill server's address family
	serv_addr.sin_family = AF_INET;

	// Server should allow connections from any ip address
	serv_addr.sin_addr.s_addr = INADDR_ANY;

	// 16 bit port number on which server listens
	// The function htons (host to network short) ensures that an integer is interpretted
	// correctly (whether little endian or big endian) even if client and server have different architectures
	serv_addr.sin_port = htons(5805);

	// Attach the server socket to a port. This is required only for server since we enforce
	// that it does not select a port randomly on it's own, rather it uses the port specified
	// in serv_addr struct.
	if (bind(sock_descriptor, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
			< 0)
		printf("Failed to bind\n");

	// Server should start listening - This enables the program to halt on accept call (coming next)
	// and wait until a client connects. Also it specifies the size of pending connection requests queue
	// i.e. in this case it is 5 which means 5 clients connection requests will be held pending while
	// the server is already processing another connection request.
	listen(sock_descriptor, 5);

	SmartDashboard::PutNumber("Waiting for connection...",1);
	printf("Waiting for connection...\n");
	unsigned int size = sizeof(client_addr);

	// Server blocks on this call until a client tries to establish connection.
	// When a connection is established, it returns a 'connected socket descriptor' different
	// from the one created earlier.
	conn_desc = accept(sock_descriptor, (struct sockaddr *) &client_addr,
			&size);
	if (conn_desc == -1)
		printf("Failed accepting connection\n");
	else
		printf("Connected\n");

	// The new descriptor can be simply read from / written up just like a normal file descriptor
	if (read(conn_desc, buff, sizeof(buff) - 1) > 0)
		printf("Received %s", buff);

	else
		printf("Failed receiving\n");
Thanks!
  #2   Spotlight this post!  
Unread 07-02-2015, 21:27
Ben Wolsieffer Ben Wolsieffer is offline
Dartmouth 2020
AKA: lopsided98
FRC #2084 (Robots by the C)
Team Role: Alumni
 
Join Date: Jan 2011
Rookie Year: 2011
Location: Manchester, MA (Hanover, NH)
Posts: 520
Ben Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud ofBen Wolsieffer has much to be proud of
Re: Using the "Team Use" TCP ports

I know this doesn't answer your question, but you might want to take a look at NetworkTables and/or the SmartDashboard. They make communication between the DS and robot really easy without worrying about debugging network code. Even if you do not want to use the SmartDashboard, you can create your own tables for use in custom applications.
__________________



2016 North Shore District - Semifinalists and Excellence in Engineering Award
2015 Northeastern University District - Semifinalists and Creativity Award
2014 Granite State District - Semifinalists and Innovation in Control Award
2012 Boston Regional - Finalists
  #3   Spotlight this post!  
Unread 07-02-2015, 21:42
tstew's Avatar
tstew tstew is offline
Alumni
AKA: Timothy Steward
FRC #3928 (Team Neutrino)
Team Role: Alumni
 
Join Date: Mar 2014
Rookie Year: 2013
Location: Ames, IA
Posts: 21
tstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud oftstew has much to be proud of
Re: Using the "Team Use" TCP ports

Quote:
Originally Posted by pensono View Post
The address of the roboRIO is determined by DCHP. This makes it impossible to know for sure what address to connect to from the laptop. I think the driver station software gets around this by using mDNS, but there's no support for mDNS in something like winsock.
You can give your roboRIO a static IP address through the roboRIO Webdashboard. Then, you can just access the roboRIO through this IP address. mDNS should still work, so I don't think it will break anything.
  #4   Spotlight this post!  
Unread 07-02-2015, 21:44
yash101 yash101 is offline
Curiosity | I have too much of it!
AKA: null
no team
 
Join Date: Oct 2012
Rookie Year: 2012
Location: devnull
Posts: 1,191
yash101 is an unknown quantity at this point
Re: Using the "Team Use" TCP ports

I'm just wondering but why are you using two servers? TCP is bi-directional. If you really want to, you can thread your server and establish an incoming and outgoing connection.
5800-5810 are the only ports that you can use on the RoboRIO. The rest are firewalled off. I'm not sure about networked coprocessors. I'm sure that there are no restrictions on those. The FMS might not even care about them even being there. Just to be on the safe side, just use 5800-5810 on all devices.
  #5   Spotlight this post!  
Unread 07-02-2015, 23:48
virtuald's Avatar
virtuald virtuald is offline
RobotPy Guy
AKA: Dustin Spicuzza
FRC #1418 (), FRC #1973, FRC #4796, FRC #6367 ()
Team Role: Mentor
 
Join Date: Dec 2008
Rookie Year: 2003
Location: Boston, MA
Posts: 1,079
virtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant futurevirtuald has a brilliant future
Re: Using the "Team Use" TCP ports

mDNS should work through winsock.
__________________
Maintainer of RobotPy - Python for FRC
Creator of pyfrc (Robot Simulator + utilities for Python) and pynetworktables/pynetworktables2js (NetworkTables for Python & Javascript)

2017 Season: Teams #1973, #4796, #6369
Team #1418 (remote mentor): Newton Quarterfinalists, 2016 Chesapeake District Champion, 2x Innovation in Control award, 2x district event winner
Team #1418: 2015 DC Regional Innovation In Control Award, #2 seed; 2014 VA Industrial Design Award; 2014 Finalists in DC & VA
Team #2423: 2012 & 2013 Boston Regional Innovation in Control Award


Resources: FIRSTWiki (relaunched!) | My Software Stuff
  #6   Spotlight this post!  
Unread 07-02-2015, 23:49
Alan Anderson's Avatar
Alan Anderson Alan Anderson is offline
Software Architect
FRC #0045 (TechnoKats)
Team Role: Mentor
 
Join Date: Feb 2004
Rookie Year: 2004
Location: Kokomo, Indiana
Posts: 9,113
Alan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond repute
Re: Using the "Team Use" TCP ports

Quote:
Originally Posted by pensono View Post
I think the driver station software gets around this by using mDNS, but there's no support for mDNS in something like winsock.
Have you tried it? I don't use C++ or Winsock, so I can't check it myself. I thought the mDNS support installed on the Driver Station computer would be usable by the getaddrinfo() function.
  #7   Spotlight this post!  
Unread 09-02-2015, 23:56
pensono pensono is offline
Registered User
FRC #5495
 
Join Date: Jan 2015
Location: Snohomish, WA
Posts: 15
pensono is an unknown quantity at this point
Re: Using the "Team Use" TCP ports

Thanks for your replies guys!

I thought static IP addresses could only be given through the router, which is reset at the beginning of competitions, but assigning it through the roboRIO will do the trick.

About the port numbers, I saw that the server code running on the roboRIO opens a new port for incoming connections, which would most likely end up being blocked by the firewall. Would it make more sense to wait for a connection on the driver station end? That would allow the port for outbound connections from the roboRIO to be known and assigned to. I'm not super experienced with network code, but optimally I'll find a way to make a P2P connection.

As for network tables, I decided against them because, as I understand it, you would need an additional library to access them. Network tables also come with bandwidth overhead, and I've run into a race condition with them before.

Thanks again!
Closed Thread


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -5. The time now is 12:15.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi