i'm trying to build a server with a PIC24F.
This is a piece of code i'm isuing:
switch(TCPServerState) {
case SM_HOME:
// Allocate a socket for this server to listen and accept connections on
socket.Socket = TCPOpen(0, TCP_OPEN_SERVER, SERVER_PORT, TCP_PURPOSE_GENERIC_TCP_SERVER);
if(socket.Socket != INVALID_SOCKET) {
TCPServerState = SM_LISTENING;
}
break;
case SM_LISTENING:
// See if anyone is connected to us
//if(TCPIsConnected(socket.Socket)) {
if(!TCPWasReset(socket.Socket)){
if(socket.Connected == 0) {
socket.Connected = 1;
printf("Socket is CONNECTED: %d\n", socket.Socket);
}
uint16_t avaible = TCPIsGetReady(socket.Socket);
// Some stuff
}
else if(socket.Connected == 1){
printf("Socket RESET: %d\n", socket.Socket);
TCPServerState = SM_CLOSING;
}
break;
case SM_CLOSING:
// Close the socket connection.
socket.Connected = 0;
TCPClose(socket.Socket);
TCPServerState = SM_HOME;
printf("Socket is CLOSED: %d\n", socket.Socket);
break;
}
All works fine if i close my client socket properly, but if i disconnect ethernet cable i am not able to detect disconnection and my code does not close the socket because TCPWasReset still FALSE(or TCPIsConnected still TRUE).
So how can i detect the disconnection of network cable(without add a software keep_alive implementation) ?
Thanks
Check a few items:
Call TickInit(); before StackInit();
Select the correct TIMER1 clock source for your application - internal clock or external clock (T1CON.TCS)
Otherwise, just use a debugger on the keepalive logic in TCP.C, which should default to 10 seconds in the latest Microchip Library for Applications TCP/IP stack 5.42.08.
Related
I've hacked apart the ESP32 BLE arduino sketches to do what I want. The server side is easy. Please see code below:
if (con == 0){
digitalWrite(LED, LOW);
}
if (con == 1){
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
}
if (deviceConnected) {
pCharacteristic->setValue((uint8_t*)&value, 4);
pCharacteristic->notify();
value++;
delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
con = 1;
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
con = 0;
}
This works exactly how I want. It simply sits idle doing nothing, when a device connects to the BLE server then it will flash an LED.
No problems there, even though I suspect my code isn't 'that pretty.
What i'm having trouble doing however is creating an ESP32 client to connect to the BLE device.
The client has the name set as
BLEDevice::init("BOX_A1");
The example code seems to want UID for both the service and characteristic. Is there any way to just connect to the short advertised name? No data is being shared, it's just simply acting as a beacon to identify a box when connected to.
Thanks
Andrew
You can't connect to a device using the advertised name, not directly at least.
If you want to use the advertised name you have to scan for all BLE devices around you and select the one matching your name. The BLE scan example shows you how this is done. The code scans for a scanTime of 5 seconds, waits 2 seconds and starts scanning again:
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}
The example just prints the amount of found devices, you want to search through them and look for the correct name. The BLEScan returns an object of type BLEScanResults. You can access the found devices using getDevice with an index. Something like this might work to print the names of all found devices:
BLEAdvertisedDevice device;
for (int i = 0; i < foundDevices.getCount(); ++i) {
device = foundDevices.getDevice(i);
Serial.println(device.getName().c_str());
}
Now you can compare the names and work with the correct device.
To my understanding,
You want the client to connect to the server with given advertised name.
After connection is success, server turns on led.
You do have notification service running on server, but your client isn't interested.
Below is the client code which only connects to server with name "BOX_A1".
First Set our callback function that checks if device name matches when scanner discovers the devices:
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice)
{
if (advertisedDevice.getName() == "BOX_A1")
{
advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
foundDevice = new BLEAdvertisedDevice(advertisedDevice);
deviceFound = true;
Serial.print("Device found: ");
Serial.println(advertisedDevice.toString().c_str());
}
}
};
Use the BLEAdvertisedDevice object i.e. foundDevice object to connect to this server.
BLEClient* connectToServer(BLEAdvertisedDevice* device) {
BLEClient* pClient = BLEDevice::createClient();
if (pClient->connect(device)){ // Connect to the remote BLE Server.
Serial.println(" - Connected to server");
return pClient;
}
else{
Serial.println("Failed to Connect to device");
return NULL;
}
}
Use following line to call this connect function, it return the client object which can be used to disconnect from server.
if(deviceFound==true){
BLEClient* myDevice = connectToServer(device);
if(myDevice!=NULL){
Serial.print("Connected to the BLE Server: ");
Serial.println(device->getName().c_str());//print name of server
//DO SOME STUFF
//disconnect the device
myDevice->disconnect();
Serial.println("Device disconnected.");
}
}
This was the client side.
At server side to set the connection status flag use the following:
//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("Client Connected");
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
Serial.println("Client Disconnected");
deviceConnected = false;
}
};
I implemented a small tcp client on STM32F7 with freeRtos and LwIP and netconn api.
I can establish a connection with the server and send some data to the network. My problem is a huge delay between the command and when I can actually see the ethernet data on the network (seconds..). Seems like the data is buffered before sending it in one go.
I'm aware of the TCP_NODELAY flag and I set it (with tcp_nagle_disable(conn->pcb.tcp)), but it doesn't make a difference. Ethernet payload is around 50 bytes, TCP_MSS is 1460.
The netconn api sees the data as sent (netbuffer structure is updated, tcp_write() and tcp_output() are called with no errors), but I have the impression that after low_level_output() is called and the data buffer is passed to the DMA (with HAL_ETH_TransmitFrame()) it stays there until something happened and 3 or 4 ethernet packets are sent in a go.
I don't want to wait forever for a reply and I set a timeout on netconn_recv(), enabling LWIP_SO_RCVTIMEO and calling netconn_set_recvtimeout(). I set up the server to answer with an echo but even with a timeout of 500ms I loose most of the replies.
Here some code:
conn = netconn_new(NETCONN_TCP);
if (conn != NULL)
{
err = netconn_bind(conn, IP_ADDR_ANY, 0);
if (err == ERR_OK)
{
connect_error = netconn_connect(conn, &dest_addr, SRV_PORT);
if (connect_error == ERR_OK)
{
// set a timeout to avoid waiting forever
netconn_set_recvtimeout(conn, 500);
//TCP_NODELAY
tcp_nagle_disable(conn->pcb.tcp);
osSemaphoreRelease(tcpsem); // signal tcpsend
if (netconn_recv(conn, &buf) == ERR_OK)
{
//Parse message
do
{
// do stuff..
}
while (netbuf_next(buf) >0);
netbuf_delete(buf);
} else {
// TIMEOUT
}
}
/* Close connection */
netconn_close(conn);
}
netconn_delete(conn);
}
vTaskDelete(tcpsendTaskHandle);
vTaskDelete(NULL);
tcpsend
void tcpsend (void *data, size_t len)
{
// send the data to the connected connection
netconn_write(conn, data, len, NETCONN_NOFLAG);
}
tcpsend
static void tcpsend_thread (void *arg)
{
for (;;)
{
// semaphore must be taken before accessing the tcpsend function
osSemaphoreAcquire(tcpsem, portMAX_DELAY);
// build msg
if (ethPrepare(ðMsg) == ERR_OK)
{
// send the data to the server
tcpsend(ðMsg, ethMsg.ncSize);
}
vTaskDelay(100);
}
}
Found the problem:
I forgot to set also the TxBuffer memory as not cacheable bufferable..
Once I added the memory configuration on the loader script and in ethernetif.c also for the tx buffer (I had it only for he rx) I could see the ethernet packets right away.
I am working with some protocol on my Windows 10 pro with VC++ 2013 Community, basically includes three steps:
client sends a GET header (e.g. authentication, etc)
server returns a HTTP header (e.g. status code 200 if everything is fine)
then server keeps sending binary data stream after the HTTP header
I send the header, and call recv() in blocking mode to receive data from server through the TCP stream. However, the recv() blocks, never return.
I use WireShark to "follow" the TCP stream, and it shows that server does keep sending binary data, and I do see ACK message from client side to acknowledge every segment it receives. However, recv() still blocks, and never returns.
I tried to use:
pure C implementation over WinSock
C# using TcpClient
C++ with Boost Asio
non-blocking WinSock (as in this article)
The first version was implemented in WinHTTP, and eventually got Timeout.
None of them can receive any data. However, the WireShark can still tell that the server keeps sending binary data.
I tried to turn off my firewall, but the problem still there.
The most weird thing is my first implementation actually did successfully get data from recv(), about two days ago. On that day, recv() returned three times, and then blocked again. The next day, the same implementation, recv() never be able to return anything.
I am really confused. Thank you!
Here is the code, blocking Winsock version:
WSADATA wsaData;
int iResult;
SOCKET ConnectSocket = INVALID_SOCKET;
struct sockaddr_in clientService;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
//----------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for connecting to server
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
clientService.sin_family = AF_INET;
auto ip = gethostbyname(name);
clientService.sin_addr = *(reinterpret_cast<struct in_addr *>(ip->h_addr));
clientService.sin_port = htons(DEFAULT_PORT);
//----------------------
// Connect to server.
iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
printf("Unable to connect to server: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
Since the shutdown code is a copy/paste from the microsoft page (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx) - I suppose that is how they indicate sending has completed. I believe this explains the issue you're having (from the above page):
Note When issuing a blocking Winsock call such as recv, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread. Issuing another blocking Winsock call inside an APC that interrupted an ongoing blocking Winsock call on the same thread will lead to undefined behavior, and must never be attempted by Winsock clients.
I actually just realized that I've only ever used non-blocking sockets and always have the receiving code on its own thread. So try adding this:
iResult = ioctlsocket(m_socket, FIONBIO, &iMode);
From here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx
Note: You're going to get mostly a series of failed attempts to receive data from the socket - so you'll need to handle those and you'll also not want to tight loop.
I use buildroot cross toolchain to compile Raspberry application from my computer (Ubuntu X86).
I'm developping a TCP serveur that allows a connection on 5003 (0x138B) TCP port number. When I'm start the server, that's right but my server wait a connection on 35603 (0x8B13) TCP port number (check with netstat -a).
It seems to be an endianness problem but I don't know how to resolve.
Can you help me please?
Thanks.
thanks for your answer.
I agree it's very strange. I don't think the code is the problem. It's working well on other platform.
Please find the code below:
/*Create the server */
int CreateServeur (unsigned short port, int *sock_srv, int nb_connect)
{
int l_ret = -1;
struct sockaddr_in l_srv_addr;
/* address initialisation */
printf("creation serveur port %i\n", port);
memset ((char*) &l_srv_addr,0, sizeof (struct sockaddr_in));
l_srv_addr.sin_family = PF_INET;
l_srv_addr.sin_port = port;
l_srv_addr.sin_addr.s_addr = htonl (INADDR_ANY);
/* main socket creation */
if ((*sock_srv = socket (PF_INET, SOCK_STREAM, 0)) <= 0)
{
printf("server socket creation error");
}
else
{
if (bind (*sock_srv, (struct sockaddr *) &l_srv_addr, sizeof (struct sockaddr_in)) == -1)
{
close (*sock_srv);
printf("bind socket error");
}
else
{
if (listen (*sock_srv, nb_connect) == ERROR)
{
close (*sock_srv);
printf("listen socket error");
}
else
{
l_ret = 0;
}
}
}
return (l_ret);
}
This function doesn't return any error. The first log (printf("creation serveur port %i\n", port);) display the good port (5003) but the server wait connexion on port 35603 (netstat -a).
If it's not a endianness problem, I don't understand.
I am new to this environment as far as UDP protocols and sending/receiving data via networks. I have read the other post regarding this kind of issue but I am not sure how to fix my problem:
I have just upgraded a PC to Windows 7 from XP. This upgrade was due to my application needs to run on Win7. I have NOT changed the was our UDP stream is broadcasted. With the upgrade I can no longer run the older version of my application becasue the UDP stream doesn't seam to get to my application.
I have turned off all firewalls and am running everything as admin.
This is how my setup is:
Code is running on ip: 192.168.2.1
UDP is sent from 192.168.2.1 to 192.168.2.87 and then broadcasted to 192.168.2.255
I used to be able to see this UDP stream with my old application on a seperate computer: 192.168.2.12
If I change my UDP stream to go directly to 192.168.2.12 ip, then my application works, but then the UDP is not broadcasted anymore. I need the UDP to be able to be read by more than one computer.
Here is my wireshark out put for the UDP Stream:
Source: 192.168.2.87
Destination: 192.168.2.255
Protocol: UDP Info:
Sorce Port: 6601 Destination Port: 6601
I have tried hard coding my c-code to listen to any possibility I can think of, aka the sender addr function:
senderAddr.sin_addr.s_addr = htonl(INADDR_ANY);
To something like:
senderAddr.sin_addr.s_addr = inet_addr("192.168.2.212")
This is the code to init the I/O buffer:
// UDP Receiver Declarations -
SOCKET SockIn = INVALID_SOCKET;
SOCKADDR_IN senderAddr;
int senderSize = sizeof(senderAddr);
u_short PortIn = 6601;
int timeout = 1;
//===================<Callbacks::Callbacks>==================
//
// Summary: Constructor
//
//=============================================================================
Callbacks::Callbacks(RTUserIntegrationI &a_rIntegration)
: m_rIntegration(a_rIntegration)
, m_pUDPInput(NULL)
{
}
//=====================<Callbacks::~Callbacks>===============
//
// Summary: Destructor
//
//=============================================================================
Callbacks::~Callbacks()
{
}
//=====================<Callbacks::InitIOBuffers>====================
//
// Summary: Init function for the IO buffer
//
//=============================================================================
void Callbacks::vInitIOBuffers()
{
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
WSADATA WSAData;
UInt Size = 0;
// UDP Declarations -
// Initialize the member pointers to buffers
bufferin = m_rIntegration.pGetIOBuffer(Input_Buffer);
if (bufferin != NULL)
m_pUDPInput = static_cast<InputData*>(bufferin->pGetDataAddress(Size));
// UDP Receive -
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("\nCould not open WSA connection");
WSACleanup();
}
SockIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (SockIn == INVALID_SOCKET)
{
printf("\nCould not create socket.");
closesocket(SockIn);
WSACleanup();
}
senderAddr.sin_family = AF_INET;
senderAddr.sin_port = htons(PortIn);
senderAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (setsockopt(SockIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) != INVALID_SOCKET)
{
printf("\nSet SO_REUSEADDR: ON.");
}
if (bind(SockIn, (struct sockaddr *) &senderAddr, senderSize) == -1)
{
printf("\nCould not bind socket.");
closesocket(SockIn);
WSACleanup();
}
setsockopt(SockIn, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));
}
I have the receive port number hard coded to 6601.
The code above works fine and the computer sees and reads the broadcasted UDP in Windows XP but ceases to work in Windows 7.
Any suggestions would be greatly appreciated.
ADDED:
192.168.2.1 generates the UDP stream--->sent to 192.168.2.87---> broadcasted on 192.168.2.255 ---> Notheing has changed on any of those computers....... I then have two computers (one XP and one Windows 7) than listen to the 2.255 ip. XP is getting the UDP and Win7 is not.