Why is my TCP system faster than UDP one? - java

I have two (client - server - client) system. First one uses TCP and second one uses UDP. It is interesting that my TCP using system is faster than UDP using one when transferring files in size 5-6 mb. Does problem occurs because of my coding mistakes or can that happen?
TCP Client
try {
socket = new Socket("localhost", 7755);
} catch (Exception e) {
System.out.println(e.getMessage().toString());
}
out = new PrintWriter(socket.getOutputStream(), true);
int i = 0;
while (file.hasNext()) {
String line = file.nextLine();
if (!line.isEmpty()) {
out.println(line);
}
i++;
}
TCP Server
try {
serverSocketA = new ServerSocket(7755);
serverSocketB = new ServerSocket(7760);
} catch (Exception e) {
System.out.println("Port error!");
}
System.out.println("Server is ready...");
clientSocketA = serverSocketA.accept();
clientSocketB = serverSocketB.accept();
PrintWriter out = new PrintWriter(clientSocketB.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocketA.getInputStream()));
while((dataFromClientA = in.readLine()) != null) {
out.println(dataFromClientA);
}
UDP Server
private static byte[] buf = new byte[6];
static Scanner file;
public static void main(String[] args) throws IOException{
long startTime = System.currentTimeMillis();
socket = new DatagramSocket();
address = InetAddress.getByName("localhost");
file = new Scanner(new File("sentfile.txt"));
DatagramPacket packet;
while (file.hasNext()) {
String line = file.nextLine();
if (!line.isEmpty()) {
buf = line.getBytes();
packet = new DatagramPacket(buf, buf.length, address, 7765);
socket.send(packet);
}
}
UDP Client
private static byte[] buffer = new byte[6];
private static byte[] buffer2 = new byte[6];
private static boolean running;
static PrintWriter writer;
public static void main(String[] args) throws IOException {
udpSocketB = new DatagramSocket();
address = InetAddress.getByName("localhost");
udpSocketA = new DatagramSocket(7765);
running = true;
DatagramPacket packet;
while(running) {
packet = new DatagramPacket(buffer, buffer.length);
udpSocketA.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
packet = new DatagramPacket(buffer, buffer.length, address, port);
String received = new String(packet.getData(), 0, packet.getLength());
DatagramPacket packetToB;
buffer2 = received.getBytes();
packetToB = new DatagramPacket(buffer2, buffer2.length, address, 7770);
udpSocketB.send(packetToB);
if (received.equals("end")) {
running = false;
continue;
}
}
I just add client1 and server codes and rest is similar. What could be the reason?

When you write over a TCP socket, it will coalesce bytes if possible into an MTU of data of around ~1500 bytes making the overhead of the packet header relatively small.
When you write each line in its own UDP packet it has an overhead for each line, possibly more than the actual data sent.
Note: in neither case do you need to read a line at a time. You can read say a byte[] of 1 KB at a time and print that.
public class TCPClient {
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket("localhost", 7755);
FileInputStream fis = new FileInputStream(args[0])) {
byte[] bytes = new byte[1024];
OutputStream out = socket.getOutputStream();
for (int len; (len = fis.read(bytes)) > 0; ) {
out.write(bytes, 0, len);
}
}
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7755);
System.out.println("Server is ready...");
try (Socket socket = serverSocket.accept()) {
byte[] bytes = new byte[1024];
for (int len; (len = socket.getInputStream().read(bytes)) > 0; )
System.out.write(bytes, 0, len);
}
}
}
You can do the same thing with UDP, transfering 1 KB at a time and get a similar throughput.
NOTE: UDP is lossy, so you might lose packets, or get them out of order.

TCP has been heavily optimized by some of the greatest networking experts in the world. It's specifically designed for sending streams of data over IP networks as quickly and efficiently as possible. It's tied into the kernel and they are heavily optimized as a unit on most modern platforms. You're not going to outperform it unless it does something that you don't need and you can obtain a significant benefit from not doing that thing.

Related

DataInputStream readert blocks

I'm reading and writing bytes on an open socket. This is my code.
#Test
public void testSingleRequest() throws IOException {
Server server = new Server(9000, 100);
new Thread(server).start();
Socket clientSocket = new Socket("localhost", 9000);
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
String payload = "a";
byte[] load = buildPushPayload(payload);
out.write(load);
DataInputStream in = new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));
byte[] buffer = new byte[128];
for (int i = 0; i <128 ; i++) {
int read = in.read(buffer, 0, 128);
}
out.close();
server.stop();
assertEquals(0, buffer[0]);
Since I'm reading a fixed length, I believe the for loop shouldn't block, but it still does. How do I get the loop to unblock?

Sending double from matlab to java via UDP-packets

I'm trying to send doubles from Matlab(Simulink) to java.
This is my code:
public static void main(String[] args) throws SocketException, UnknownHostException, IOException {
DatagramSocket socket = new DatagramSocket(25000);
byte[] buf = new byte[512];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
socket.receive(packet);
String msg = new String(buf, 0, packet.getLength());
Double x = ByteBuffer.wrap(buf).getDouble();
System.out.println(x);
packet.setLength(buf.length);
}
}
I'm getting values but they really don't make sense...
Most likely you are sending doubles as little-endian but ByteBuffer assumes "network order" which is big-endian.
try
DatagramSocket socket = new DatagramSocket(25000);
byte[] buf = new byte[512];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
DoubleBuffer db = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
while (true) {
socket.receive(packet);
db.limit(packet.getLength() / Double.BYTES);
double x = db.get(0);
System.out.println(x);
}
Note: UCP is lossy, so some packets will be lost.

How to make a serversocket listen to many ports and make different clients connect to different ports

I had a server client application to transfer files where i need to connect to many clients from one server using sockets. I tried, and got the connections but when compared to a single connection the speed is decreasing when connected to more number of clients so i got an idea to open more ports and connect to different clients from server on multiple ports
This is my code for opening a serversocket
try {
serverSocket = new ServerSocket(SocketServerPORT);
serverSocket1 = new ServerSocket(SocketServerPORT1);
while (true) {
socket = serverSocket.accept();
FileThread fileThread = new FileThread(socket);
fileThread.start();
socket1 = serverSocket1.accept();
FileTxThread fileTxThread = new FileTxThread(socket1);
fileTxThread.start();
}
This is the code for sending files from server
DataOutputStream dos=new DataOutputStream(socket.getOutputStream());
dos.writeInt(f.size());
for(File file1:f){
long length = file1.length();
dos.writeLong(length);
String name = file1.getAbsolutePath();
System.out.println(name);
dos.writeUTF(name);
FileInputStream in = new FileInputStream(file1);
int bs=65508;
byte[] b= new byte[bs];
int theByte = 0;
while((theByte = in.read(b,0,bs)) != -1) dos.write(b,0,theByte);
in.close();
This is my client side code(my client is android device)
private class ClntThread extends Thread {
String dstAddress;
int dstPort;
ClntThread(String address, int port) {
dstAddress = address;
dstPort = port;
}
#Override
public void run() {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
DataInputStream dis = new DataInputStream(socket.getInputStream());
int filescount=dis.readInt();
File[] files=new File[filescount];
for(int i = 0; i < filescount; i++)
{
files[i] = new File(dirpath + "/" + filesname);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(files[i]));
int bs=65508;
byte[] b=new byte[bs];
int j=0;
while ((j = dis.read(b, 0, bs))!=-1){
bos.write(b, 0, j);
}
bos.flush();
bos.close();
}
dis.close();
socket.close();
Here how to open different ports on server side and how to connect to server from client as i am mentioning the port number on client side i dont know how client will connect to the unknown port????
I am new to programming and so please give me any suggestions if my approach is wrong
Thank you..

Multicast a file to a group of users

I have a problem to send a file to a group of users. Users could receive the file was sent from server but the file would not be saved if it is less than 8kb.
Here is the code:
MulticastSocketServer
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class MulticastSocketServer{
public static void main(String[] args) {
String fileName;
String address = "235.0.0.1";
int port = 2222;
Scanner in = new Scanner(System.in);
System.out.print("Please enter file name : ");
fileName = in.next();
try (DatagramSocket serverSocket = new DatagramSocket()) {
InetAddress addr = InetAddress.getByName(address);
BufferedReader br = new BufferedReader(new FileReader(fileName + ".txt"));
DatagramPacket fn = new DatagramPacket(fileName.getBytes(),fileName.getBytes().length, addr, port);
serverSocket.send(fn);
DatagramPacket msgPacket = null;
String txt = "";
while((txt = br.readLine())!=null){
msgPacket = new DatagramPacket(txt.getBytes(),txt.getBytes().length, addr, port);
serverSocket.send(msgPacket);
System.out.println(txt);
}
}catch (IOException ex) {ex.printStackTrace();}
}
}
MulticastSocketClient
import java.io.*;
import java.net.*;
public class MulticastSocketClient {
public static void main(String[] args) throws UnknownHostException {
int port = 2222;
String address = "235.0.0.1";
InetAddress addr = InetAddress.getByName(address);
byte[] buf = new byte[64];
byte[] buf2 = null ;
try (MulticastSocket clientSocket = new MulticastSocket(port)){
clientSocket.joinGroup(addr);
DatagramPacket fn = new DatagramPacket(buf, buf.length);
clientSocket.receive(fn);
String name = new String(buf, 0, buf.length);
String fileName = name.trim();
try(PrintWriter pw = new PrintWriter(new FileWriter(fileName+"2.txt"))){
while (true) {
buf2 = new byte [1024];
DatagramPacket msgPacket = new DatagramPacket(buf2, buf2.length);
clientSocket.receive(msgPacket);
String msg = new String(buf2,0,buf2.length);
String txt = msg.trim();
pw.println(txt);
System.out.println(txt);
}
}catch(FileNotFoundException ex){ex.printStackTrace();}
} catch (IOException ex) {ex.printStackTrace();}
}
}
You're never exiting the while (true) loop, because you don't have any mechanism for transmitting end of stream, so you're never closing the PrintWriter, so it isn't flushing its final buffer, so any file < 4096 chars won't get flushed at all, so it will be zero length.
However your code has much worse problems that this. You are assuming:
the filename fits into 1024 characters
every line of the input file fits into 1024 bytes
the filename is received first
all the content packets are received
all the content packets are received in order
all the content packets are received exactly once
the length of every datagram is 1024
the data is text, not binary, and can be converted losslessly to a String
You're using UDP. That means that most of these assumptions are invalid.

Java Socket : I'm trying to generate random port numbers between a range, but connection is refused, but when I'm using a integer, it works

Client :
public class FileClient {
static int Min = 1050;
static int Max = 15000;
static int PORT = Min + (int)(Math.random() * ((Max - Min) + 1));
public static void main(String[] args) throws IOException {
Socket sock = new Socket("localhost", PORT);
if (PORT>=2000&&PORT<=2050) {
System.out.println("The rare disconnection");
sock.close();
}
System.out.println("Connection Opened");
// sendfile
File myFile = new File("input.txt");
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
System.out.println("Input Stream Opened");
bis.read(mybytearray, 0, mybytearray.length);
OutputStream os = sock.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
System.out.println("Data written to output file");
os.flush();
bis.close();
System.out.println("Input Stream Closed");
sock.close();
System.out.println("Connection Closed");
}
}
Server:
public class FileServer {
public static void main (String[] args ) throws IOException {
int XPORT = FileClient.PORT;
int bytesRead;
ServerSocket serverSocket = new ServerSocket(XPORT);
System.out.println("Listening for a client");
while(true) {
Socket clientSocket = null;
clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream();
// Writing the file to disk
// Instantiating a new output stream object
OutputStream output = new FileOutputStream("output.txt");
byte[] buffer = new byte[1024];
while ((bytesRead = in.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
// Closing the FileOutputStream handle
output.close();
}
}
}
Java Socket : I'm trying to generate random port numbers between a range, but connection is refused, but when I'm using a integer, it works. This is working for one value. I want the server to deny the connection for a few port numbers (Ex: 2000-2100)
And want the connection to be accepted and file transfer to be completed. When using integers, my file transfer works perfectly.
When you run the client you get one random number. When you run the server you get another. They're almost certainly different. There's no reason to expect this to work, and there's no reason to even try. Use a fixed port number. There are plenty available.

Categories

Resources