i have a UDP Server/Client Program wich works well.
I send the received Message from one Client back to all connected Clients, but the Output doubles after each Loop.
I think i have to reset the ListArray with the Clients, but then only the first Message will be Send.
Does somebody has any idea? Thanks!
UDP SERVER
//Listening on Port 12222
int servPort = 12222;
UdpClient client = null;
//Create a new ListArray for the connected Clients
ArrayList IPArray = new ArrayList();
try
{
//Create an instance of UdpClient
client = new UdpClient(servPort);
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
Environment.Exit(se.ErrorCode);
}
//Create an new IPEndPoint
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
//Endless loop
for (; ; )
{
try
{
//Receive a byte array with contents
byte[] byteBuffer = client.Receive(ref remoteIPEndPoint);
//Message from Client
string returnData = Encoding.ASCII.GetString(byteBuffer);
//Add connected Client IPs to ListArray
IPArray.Add(remoteIPEndPoint);
//Send the received Message back to all Clients in the ArrayList
for (int i = 0; i < IPArray.Count; i++)
{
Console.WriteLine("Handling client at " + IPArray[i] + " - " + returnData + " arraylist.Length " + IPArray.Count + "\n");
Byte[] sendBytes = Encoding.ASCII.GetBytes("Clients Send " + returnData + "\n");
client.Send(sendBytes, sendBytes.Length, (IPEndPoint)IPArray[i]);
}
Console.WriteLine("echoed {0} bytes.", byteBuffer.Length);
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
}
}
}
UDP CLIENT
//Server name or IP address
static String server = "127.0.0.1";
//Port
static int servPort = 12222;
//Convert String to an array of bytes
static string message = "ICH";
static void Main(string[] args)
{
SendReceive();
}
static byte[] sendPacket = Encoding.ASCII.GetBytes(message);
//Create an instance of UdpClient
static UdpClient client = new UdpClient();
static void SendReceive()
{
try
{
//Send the string to the specified Server and Port
client.Send(sendPacket, sendPacket.Length, server, servPort);
Console.WriteLine("Sent {0} bytes to the server...", sendPacket.Length);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
//Attempt Message reply receive
byte[] rcvPacket = client.Receive(ref remoteIPEndPoint);
Console.WriteLine("Received {0} bytes from {1}: {2}",
rcvPacket.Length, remoteIPEndPoint,
Encoding.ASCII.GetString(rcvPacket, 0, rcvPacket.Length));
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
}
//Console.ReadKey();
//client.Close();
Thread.Sleep(500);
//Endless Loop
SendReceive();
}
UDP SERVER :
The Array with the iP Adresses grows with every Message from the
Client, but i want only the last Message that the Clients has send.
If that is the requirement, then there is no need of the loop. Also, without the help of arraylist, you can display the details of individual clients using the remoteIPEndPoint itself. That is the neater way to do what you want.
Remove the following lines from the UDP Server :
...
//Send the received Message back to all Clients in the ArrayList
for (int i = 0; i < IPArray.Count; i++)
{
Console.WriteLine("Handling client at " + IPArray[i] + " - " + returnData + " arraylist.Length " + IPArray.Count + "\n");
Byte[] sendBytes = Encoding.ASCII.GetBytes("Clients Send " + returnData + "\n");
client.Send(sendBytes, sendBytes.Length, (IPEndPoint)IPArray[i]);
}
...
You need to display the IP-Address and the port number of the client which sent the message. Instead, add the following lines :
//1. Now, you can show the count, but, you can get the indiviudal client detail
//using the remoteIPEndPoint, there is no need of iterating through the array.
Console.WriteLine("This message was sent from " + remoteIPEndPoint.Address.ToString() +
" on their port number " +
remoteIPEndPoint.Port.ToString() + " - " + returnData + "\n");
//2. Then send the data back to the individual client without using ArrayList,
// by passing the client's IPEndPoint in the Send() method.
Byte[] sendBytes = Encoding.ASCII.GetBytes("Clients Send " + returnData + "\n");
client.Send(sendBytes, sendBytes.Length, remoteIPEndPoint);
What it does is that it shows the IP-Address and the port number of the client which sent the message to the server.\
Also, the current way is not a better way for network/socket programming. You should always use separate threads(limit them in a pool using ConnectionQueue) for receving each client's message. Use a ConnectionQueue to maintain an order of threads (which can be reused for each new client-request).
Related
I am using SS7 Stack to receive IDP packets and forward to core using a new dialog.
I am able to successfully forward the request using following code:
#Override
public void onInitialDPRequest(InitialDPRequest arg0) {
try {
String refId = StringUtility.createRefId("sc");
logger.info("[" + refId + "] IDP Recieved");
String outgoingGTDigits = "92308985051";
int calledSSN = 146;
int remotePC = 3003;
SccpAddress remoteAddress = MapUtilities.getSccpAddress(RoutingIndicator.ROUTING_BASED_ON_GLOBAL_TITLE, outgoingGTDigits, calledSSN, remotePC);
arg0.getCAPDialog().setRemoteAddress(remoteAddress);
logger.debug("[" + refId + "] Forwading to Core with remoteAddress [" + remoteAddress + "]");
InitialDPRequestImpl initialDPRequestImpl = (InitialDPRequestImpl) arg0;
Invoke invoke = SCCPProxy.tcapStack_cap.getProvider().getComponentPrimitiveFactory()
.createTCInvokeRequest(InvokeClass.Class2);
invoke.setTimeout(_Timer_CircuitSwitchedCallControl_Short);
OperationCode oc = SCCPProxy.tcapStack_cap.getProvider().getComponentPrimitiveFactory().createOperationCode();
oc.setLocalOperationCode((long) CAPOperationCode.initialDP);
AsnOutputStream aos = new AsnOutputStream();
initialDPRequestImpl.encodeData(aos);
Parameter p = SCCPProxy.tcapStack_cap.getProvider().getComponentPrimitiveFactory().createParameter();
p.setTagClass(initialDPRequestImpl.getTagClass());
p.setPrimitive(initialDPRequestImpl.getIsPrimitive());
p.setTag(initialDPRequestImpl.getTag());
p.setData(aos.toByteArray());
invoke.setParameter(p);
invoke.setOperationCode(oc);
// Create a new dialog
Dialog clientDialog = SCCPProxy.tcapStack_cap.getProvider().getNewDialog(arg0.getCAPDialog().getLocalAddress(), remoteAddress);
invoke.setInvokeId(clientDialog.getLocalDialogId());
clientDialog.sendComponent(invoke);
logger.debug("[" + refId + "] set invoke id " + clientDialog.getLocalDialogId());
//long[] _ACN_ = new long[]{0, 4, 0, 0, 1, 0, 19, 2};
ApplicationContextName acn = SCCPProxy.tcapStack_cap.getProvider().getDialogPrimitiveFactory()
.createApplicationContextName(arg0.getCAPDialog().getApplicationContext().getOID());
// Create begin request
TCBeginRequest tcbr = SCCPProxy.tcapStack_cap.getProvider().getDialogPrimitiveFactory().createBegin(clientDialog);
tcbr.setApplicationContextName(acn);
clientDialog.send(tcbr);
logger.info("[" + refId + "] Forwaded to core with id: " + clientDialog.getLocalDialogId());
} catch (Exception ex) {
logger.error("Exception: ", ex);
}
}
TCPDump
Now when core node replies to this packet (packet #3) . I am getting CAP Dialog not found for Dialog Id n in sigtran logs.
Sigtran Logs
Am I forwarding packet correctly?
It's a little bit more complicated.
I may assume that you want to handle all in same Sbb..
When you create a new capDialog(clientDialog in your case), it created with new TCAP otid and dtid. So even when you receive a response in terms of new capDialog, you have to correlate it with original capDialog.
Sbb knows only about ActivityContext from initial event, as you didn't attach sbbLocalObject to new ActivityContext.
It's better to use Parent->Child architecture for such tasks. Parent Sbb handles all original dialog events. Child Sbb creates new dialog, attach sbbLocalObject to new ActivityContext and handles all related events for new dialog.
I was able to forward packet and get reply without any issue by doing following changes:
Have to create new dialog like this
CAPDialogCircuitSwitchedCall capDialog = capProvider.getCAPServiceCircuitSwitchedCall().createNewDialog(arg0
.getCAPDialog().getApplicationContext(), proxyOwnAddress, destinationAddress, arg0.getCAPDialog().getRemoteDialogId());
Copy payload from original dialog and put in new dialog
capDialog.addInitialDPRequest((int) arg0.getInvokeId(),
arg0.getServiceKey(), arg0.getCalledPartyNumber(),
arg0.getCallingPartyNumber(), arg0.getCallingPartysCategory(),
arg0.getCGEncountered(), arg0.getIPSSPCapabilities(),
arg0.getLocationNumber(), arg0.getOriginalCalledPartyID(),
arg0.getExtensions(), arg0 .getHighLayerCompatibility(),
arg0.getAdditionalCallingPartyNumber(), arg0.getBearerCapability(),
arg0.getEventTypeBCSM(), arg0 .getRedirectingPartyID(),
arg0.getRedirectionInformation(), arg0.getCause(),
arg0.getServiceInteractionIndicatorsTwo(),
arg0.getCarrier(),
arg0.getCugIndex(), arg0.getCugInterlock(),
arg0.getCugOutgoingAccess(), arg0.getIMSI(),
arg0.getSubscriberState(), arg0 .getLocationInformation(),
arg0.getExtBasicServiceCode(), arg0.getCallReferenceNumber(),
arg0.getMscAddress(), arg0 .getCalledPartyBCDNumber(),
arg0.getTimeAndTimezone(), arg0.getCallForwardingSSPending(),
arg0.getInitialDPArgExtension());
Save and Forward new dialog
dialogHashMap.put(capDialog.getLocalDialogId(), arg0.getCAPDialog());
capDialog.setReturnMessageOnError(true);
capDialog.send();
logger.info("[" + refId + "] Forwaded with id: " +
capDialog.getLocalDialogId());
Retrieve and reply
So now when I received the reply from core. I just needed to retrieve original dialog from dialogHashMap using local dialogId and reply back
I have written code for TcpListener in c# which is supposed to receive request from client socket and process the request (send the processed request to our another web service to get final response) then parse the response and send the response back to client socket which initiated the request.
Code snippet below.
Code works fine when receive few requests at a time but now in order to move this to cloud and accept multiple request. We are testing this functionality by running JMeter test on same.
We are getting throughput like 4 when we hit 100 threads per seconds (end to end test - client system to server socket to our web service and back) which should be at least 30 to match client requirement.
If we omit the end to end flow and just send back to hardcode response from server socket itself we are seeing throughput 700.
To find the root cause I have added delay while sending hardcore response (same which we need to communicate with our web service) and I can see same behavior i.e. throughput drastically downgrades = 4/3.8
It means when TcpListener is busy processing existing request it may not attend the next requests (may be I am wrong in assumption - please correct if so)
Please have a look at code and help me increasing the performance .
public void StartTCPServer()
{
Logger.Write_Info_Log("In StartTCPServer - inPort : " + AESDK_CONFIG.PORT_NO, 1, log);
try
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, AESDK_CONFIG.PORT_NO);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception Ex)
{
Logger.Write_Fatal_Log("Exception in Start Listening : " + Ex.Message, 1, log);
}
}
public void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public void ReadCallback(IAsyncResult ar)
{
String strdata = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
strdata = state.sb.ToString();
if (!string.IsNullOrEmpty(strdata))
{
// All the data has been read from the client.
if (strdata.Contains("<<CheckConnection>>"))
{
log.Info(GlobalVar.gThreadNo(GlobalVar.gintCurrentThread) + "Data Received: " + strdata);
byte[] byData1 = System.Text.Encoding.UTF8.GetBytes("<<CheckConnectionAlive>>");
Send(handler, "<<CheckConnectionAlive>>");
}
else
{
Interlocked.Increment(ref m_clientCount);
//Process incoming requests here and send response back to client
string strResponse = GetRequest(strdata, m_clientCount);
Send(handler, strResponse);
}
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
I'm using socket with O_NONBLOCK, select, keep alive connection and something like HTTP.
each server connection and client side uses a buffer to get all sent data until complete message be received
How to working:
client send data "A"
client try receive response from server
server receive but don't reply immediately
client gets timeout
server send response "A" (but client don't receive now)
another request:
client send data "B"
server send response "B"
client receive "AB" response instead only "B"
the problem is that client receives previous buffer message
source code bellow:
Server.cpp base class:
bool Server::start()
{
struct sockaddr_in client_addr;
SOCKET client_socket, max_sock;
Connection* conn;
int addrlen = sizeof(struct sockaddr_in);
std::list<Connection*>::iterator it, itr;
int response;
fd_set fdset, read_fds;
max_sock = m_socket;
FD_ZERO(&fdset);
FD_SET(m_socket, &fdset);
onStart();
while(true)
{
// make a copy of set
read_fds = fdset;
// wait for read event
response = select(max_sock + 1, &read_fds, NULL, NULL, NULL);
if(response == -1)
break;
// check for new connections
if(FD_ISSET(m_socket, &read_fds))
{
response--;
// accept connections
client_socket = accept(m_socket, (struct sockaddr*)&client_addr, &addrlen);
if(client_socket != INVALID_SOCKET)
{
conn = new Connection(*this, client_socket, &client_addr);
m_connections.push_front(conn);
// add connection to set for wait for read event
FD_SET(client_socket, &fdset);
// allow select new sock from select funcion
if(max_sock < client_socket)
max_sock = client_socket;
}
}
// check for received data from clients
it = m_connections.begin();
while(it != m_connections.end() && response > 0)
{
conn = *it;
// verify if connection can be readed
if(FD_ISSET(conn->getSocket(), &read_fds))
{
response--;
conn->receive();
if(!conn->isConnected())
{
FD_CLR(conn->getSocket(), &fdset);
// remove connection from list
itr = it;
it++;
m_connections.erase(itr);
delete conn;
continue;
}
}
it++;
}
}
onFinish(response >= 0);
return response >= 0;
}
main.cpp Server implementation:
void ClientConnection::onReceive(const void * data, size_t size)
{
const char *str, *pos = NULL;
HttpParser* p;
buffer->write(data, size);
do
{
str = (const char*)buffer->data();
if(contentOffset == 0)
{
pos = strnstr(str, buffer->size(), "\r\n\r\n");
if(pos != NULL)
{
contentOffset = pos - str + 4;
p = new HttpParser((const char*)buffer->data(), contentOffset);
contentLength = p->getContentLength();
delete p;
}
}
if(buffer->size() - contentOffset < contentLength || contentOffset == 0)
return;
proccessRequest();
keepDataStartingOf(contentOffset + contentLength);
}
while(buffer->size() > 0);
}
client side code is a simple recv send with timeout
any idea how to solve?
The first thing that comes to mind is to make the client's timeout large enough that the client won't timeout unless the server is actually dead... but I'm sure you've already thought of that. :)
So assuming that's not a good enough fix, the next thing to try is to have the client send an ID number with each request it sends. The ID number can be generated with a simple counter (e.g. for the client's first request, it tags the request with 0, for the second it tags it with 1, etc). The server, when sending its reply, will include that same ID number with the reply.
When the client receives a reply, it compares the ID number in the reply data against the current value of its counter. If the two numbers are the same, it processes the data. If not, it ignores the data. Et voila!
Is there anyway to listen for an outbound sms without having to import javax.wireless.messaging?
I'm trying to write an app that listens for an sms sent from the device then emails the message of the sms, but I get the error:
reference to Message is ambiguous, both class
javax.wireless.messaging.Message in javax.wireless.messaging and class
net.rim.blackberry.api.mail.Message in net.rim.blackberry.api.mail
match
I need to import net.rim.blackberry.api.mail.Message in order to sent an email.
Is there a way to get around this as it seems that the two packages are clashing.
My code:
public void notifyIncomingMessage(MessageConnection messageconnection) {}
public void notifyOutgoingMessage(javax.wireless.messaging.Message message) {
try {
String address = message.getAddress();
String msg = null;
if ( message instanceof TextMessage ) {
TextMessage tm = (TextMessage)message;
msg = tm.getPayloadText();
} else if (message instanceof BinaryMessage) {
StringBuffer buf = new StringBuffer();
byte[] data = ((BinaryMessage) message).getPayloadData();
msg = new String(data, "UTF-8");
Store store = Session.getDefaultInstance().getStore();
Folder[] folders = store.list(Folder.SENT);
Folder sentfolder = folders[0];
Message in = new Message(sentfolder);
Address recipients[] = new Address[1];
recipients[0]= new Address("me#us.com", "user");
in.addRecipients(Message.RecipientType.TO, recipients);
in.setSubject("Outgoing sms");
in.setContent("You have just sent an sms to: " + address + "\n" + "Message: " + msg);
in.setPriority(Message.Priority.HIGH);
Transport.send(in);
in.setFlag(Message.Flag.OPENED, true);
Folder folder = in.getFolder();
folder.deleteMessage(in);
}
} catch (IOException me) {
System.out.println(me);
}
}
}
You never should need to import anything in Java. Importing a package is just a shortcut, so that you don't have to fully type out the whole package name. If you have a class named Message that you want to use, and it exists in two packages (both of which you need), then I wouldn't import either of them.
Simply, always refer to each of them by their fully-qualified name:
net.rim.blackberry.api.mail.Message
and
javax.wireless.messaging.Message
It's just a little more typing.
I'm trying to use Smack to transfer a file between two PCs connected on the same XMPP server, but I get a weird error.
To summarize, the destination PC has a FileTransferListener registered, like so:
ftm.addFileTransferListener(new FileTransferListener() {
#Override
public void fileTransferRequest(FileTransferRequest request) {
System.out.println("Request received");
if (true) // Check to see if the request should be accepted
{
// Accept it
System.out.println("Entering FTListener because of FTRequest");
IncomingFileTransfer transfer = request.accept();
String id = request.getDescription();
String path = savePoint + System.getProperty("file.separator") + request.getFileName();
try
{
System.out.println("Receiving...");
transfer.recieveFile(new File(path));
// Information put in HashMap for later retrieval
System.out.println("IM - putting in path (" + id + "," + path + ")");
paths.put(id, path);
} catch (XMPPException e) {
logger.error("Error getting the VM file: " + e.getMessage());
}
}
else
{
// Reject it
request.reject();
logger.info("VM file transfer rejected");
}
}
});
The source PC uses an OutgoingFileTransfer like so:
try
{
String nick = destHost + "#" + this.conn.getServer() + "/Smack";
//destHost = destination host name, conn = XMPP connection
System.out.println("OFT to " + nick);
OutgoingFileTransfer.setResponseTimeout(10000);
OutgoingFileTransfer oft = ftm.createOutgoingFileTransfer(nick);
oft.sendFile(f, name); //f = file to send, name = a message
while (!oft.isDone())
{
if (oft.getStatus().equals(Status.error))
{
System.out.println("ERROR!!! " + oft.getError());
oft.cancel();
return false;
}
System.out.println(oft.getStatus());
System.out.println(oft.getProgress());
System.out.println("5 sec sleep");
Thread.sleep(5000);
}
if (oft.getStatus().equals(Status.complete))
{
System.out.println("Transfer done");
return true;
}
if (oft.getStatus().equals(Status.error))
System.out.println("Transfer failed: " + oft.getError());
return false;
} catch (XMPPException e) {
System.out.println("Error sending VM image file with the FTM : " + e.getMessage());
return false;
} catch (InterruptedException e) {
System.err.println("Error sleeping during OFT : " + e.getMessage());
return false;
}
When I try to send a file, the outgoing file transfer begins, and the destination PC receives the request, but the source PC cannot go further then the transfer negotiation.
This is seen in the source PC output...
Initial
0.0
2 sec sleep
Negotiating Transfer
0.0
2 sec sleep
Negotiating Stream
0.0
2 sec sleep
Transfer failed: null
I'm really annoyed because I don't even get a proper error message, so I don't really know what went wrong.
Has this ever happened to anyone else?
Looks like you are running into a known issue in Smack that will hopefully be fixed in the next release.
Update: This is now fixed and will be in version 3.2.1.
XMPP bytestreams are well specified, but are a rather complex topic, because there is more than one way to establish such a stream.
Your code looks right on a quick review. Now the next step would be to analyze the XMPP stanzas send between both clients and the server. This should give you a hint about the error cause. Also make sure to use smack 3.2.0 which has IBB support, which should increase the chance of a successful file transfer via XMPP.