Sending DatagramPacket by UDP - java

I'm trying to send some data by UDP. This is my code:
public class UDP {
public static void main(String args[]) throws IOException {
InetAddress inetAddress = InetAddress.getByName("239.255.42.99");
int PORT = 2225;
int BUFFER_SIZE = 10;
DatagramSocket datagramSocket = new DatagramSocket(PORT, inetAddress);
byte[] buf = new byte[BUFFER_SIZE];
String message = "0123456789";
buf = message.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
datagramPacket = new DatagramPacket(buf, buf.length);
datagramPacket.setAddress(inetAddress);
datagramPacket.setPort(PORT);
datagramSocket.send(datagramPacket);
datagramSocket.setSoTimeout(1010);
}
}
I have this error:
Exception in thread "main" java.io.IOException: Invalid argument
at java.net.PlainDatagramSocketImpl.send(Native Method)
at java.net.DatagramSocket.send(DatagramSocket.java:698)
at UDP.main(UDP.java:21)
Anyone know what I do wrong?

Try it this way:
public static void main(String args[]) throws IOException {
InetAddress inetAddress = InetAddress.getByName("239.255.42.99");
int PORT = 2225;
int BUFFER_SIZE = 10;
DatagramSocket datagramSocket = new DatagramSocket();
byte[] buf = new byte[BUFFER_SIZE];
String message = "0123456789";
buf = message.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, inetAddress, PORT);
datagramSocket.send(datagramPacket);
datagramSocket.setSoTimeout(1010);
}

Related

Java Socket Programming (Client,Bridge,Server)

The task is to
(1) Send message from Client to Server via Bridge
(2) Send back the message in UPPER CASE from server to client via Bridge
(1) is done
I am have problem with sending the message back to the client
Here are the classes:
UDPCLIENT
import java.io.*;
import java.net.*;
class UDPClient
{
public static void main(String args[]) throws Exception
{
//getting input from the user and sending to Bridge
BufferedReader inFromUser =
new BufferedReader(new InputStreamReader(System.in));
DatagramSocket clientSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("localhost");
byte[] sendData = new byte[1024];
byte[] receiveData = new byte[1024];
String sentence = inFromUser.readLine();
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 4000);
clientSocket.send(sendPacket);
//Getting data from the Bridge
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
clientSocket.receive(receivePacket);
String modifiedSentence = new String(receivePacket.getData());
System.out.println("C: FROM SERVER:" + modifiedSentence);
clientSocket.close();
}
}
UDPSERVER
import java.io.*;
import java.net.*;
class UDPServer
{
public static void main(String args[]) throws Exception
{
DatagramSocket serverSocket = new DatagramSocket(5000);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while(true)
{
//receiveing data from the bridge
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("S:RECEIVED: " + sentence);
InetAddress IPAddress = InetAddress.getByName("localhost");
// Sending data to the bridge
int port = 4000;
String capitalizedSentence = sentence.toUpperCase();
sendData = capitalizedSentence.getBytes();
DatagramPacket sendPacket =
new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
}
Bridge
import java.io.*;
import java.net.*;
/**
* Write a description of class Bridge here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class Bridge
{
public static void main(String args[]) throws Exception{
DatagramSocket bridgeSocket1 = new DatagramSocket(4000);
DatagramSocket bridgeSocket2 = new DatagramSocket();
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
DatagramPacket receivePacket;
DatagramPacket sendPacket;
InetAddress IPAddress = InetAddress.getByName("localhost");
while(true){
//Receiveing data from the UDPClient
receivePacket = new DatagramPacket(receiveData, receiveData.length);
bridgeSocket1.receive(receivePacket);
//Sending data to UDPServer
String sentence = new String(receivePacket.getData());
System.out.println("B: Data Received:" + sentence);
int port = 5000;
sendData = sentence.getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
bridgeSocket2.send(sendPacket);
// Receiving Data from the UDPServer
receivePacket = new DatagramPacket(receiveData,receiveData.length);
bridgeSocket1.receive(receivePacket);
String capitalizedSentence = new String(receivePacket.getData());
System.out.println("Capitalized Sentence in the Bridge Class: " + capitalizedSentence);
//Sending data to the UDPClient
sendData = capitalizedSentence.getBytes();
sendPacket = new DatagramPacket(sendData,sendData.length,IPAddress,5000);
bridgeSocket2.send(sendPacket);
}
}
}
You are sending the response from the server back to the server because you are using port 5000 as the destination port. But the server is running on 5000, not your client. You have to assign your client to a port as well and send the message received from the server back to the client on the defined port.
For now your sequence looks like this:
(C) ---> 4000
---> 5000
4000 <---
---> 5000
4000 <---
---> 5000
4000 <---
---> 5000
4000 <---
[...]
But it should look like this:
(C) ---> 4000
---> 5000
4000 <---
4500 <---
(assuming your client is listening on port 4500)

Make UDPServer send to UDPClient

I'm trying to send data to the client but I have not figured out
This is my code.
UDP-Client:
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
DatagramSocket datagramSocket = new DatagramSocket( );
InetAddress ipServer = InetAddress.getByName("localhost");
byte[] sendDatagram = new byte[1054];
byte[] sendDatagramB = new byte[1055];
byte[] sendDatagramC = new byte[1056];
byte[] receiveDatagram = new byte[1054];
byte[] receiveDatagramB = new byte[1055];
byte[] receiveDatagramC = new byte[1056];
while (true) {
System.out.println("Ingrese X");
String msgA = input.readLine();
System.out.println("Ingrese B");
String msgB = input.readLine();
System.out.println("Ingrese C");
String msgC = input.readLine();
sendDatagram = (msgA.getBytes());
DatagramPacket sendPacket = new DatagramPacket(sendDatagram, sendDatagram.length, ipServer, 6667);
datagramSocket.send(sendPacket);
sendDatagramB = (msgB.getBytes());
DatagramPacket sendPacketB = new DatagramPacket(sendDatagramB, sendDatagramB.length, ipServer, 6667);
datagramSocket.send(sendPacketB);
sendDatagramC = (msgC.getBytes());
DatagramPacket sendPacketC = new DatagramPacket(sendDatagramC, sendDatagramC.length, ipServer, 6667);
datagramSocket.send(sendPacketC);
}
UDP-Server:
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
DatagramSocket datagramSockets = new DatagramSocket( );
InetAddress ipServer = InetAddress.getByName("localhost");
byte[] sendDatagrams = new byte[1054];
byte[] receiveDatagrams = new byte[1054];
DatagramSocket datagramSocket = new DatagramSocket(6667);
byte[] sendDatagram = new byte[1054];
byte[] receiveDatagram = new byte[1054];
byte[] sendDatagramB = new byte[1055];
byte[] receiveDatagramB = new byte[1055];
byte[] sendDatagramC = new byte[1056];
byte[] receiveDatagramC = new byte[1056];
System.out.println("Server Start");
while (true){
DatagramPacket receivePacket = new DatagramPacket(receiveDatagram,receiveDatagram.length);
datagramSocket.receive(receivePacket);
String receive = new String(receivePacket.getData());
System.out.println(receive+"x");
InetAddress ipClient = receivePacket.getAddress();
int portClient = receivePacket.getPort();
receiveDatagram = new byte[1054];
String msgClient = "Hola Mundo";
DatagramPacket receivePacketB = new DatagramPacket(receiveDatagramB,receiveDatagramB.length);
datagramSocket.receive(receivePacketB);
String receiveB = new String(receivePacketB.getData());
System.out.println(receiveB+"y");
InetAddress ipClientB = receivePacketB.getAddress();
int portClientB = receivePacketB.getPort();
receiveDatagramB = new byte[1055];
String msgClientB = "Hola Mundo";
DatagramPacket receivePacketC = new DatagramPacket(receiveDatagramC,receiveDatagramB.length);
datagramSocket.receive(receivePacketC);
String receiveC = new String(receivePacketC.getData());
System.out.println(receiveC+"z");
InetAddress ipClientC = receivePacketC.getAddress();
int portClientC = receivePacketC.getPort();
receiveDatagramC = new byte[1056];
String msgClientC = "Hola Mundo";
Double x1 = (-portClientB - (Math.sqrt((portClient*portClientB - ((4*portClient*portClientC))))))/ (2 * portClientC);
Double x2 = (-portClientB + (Math.sqrt((portClient*portClientB - ((4*portClient*portClientC))))))/ (2 * portClientC);
String xa = String.valueOf(x1);
String xb = String.valueOf(x2);
System.out.println("El Resultado de x1 es = "+" "+x1);
System.out.println("El Resultado de x1 es = "+" "+x2);
}
I suppose to send String XA and XB to the client.
I don't know what you are really doing with udp socket but generally a server must support all the requests including a protocol from clients.
This is what my udp socket server looks like from your source as follows:
package justtest;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(6667);
byte[] sendDatagram = new byte[1054];
byte[] receiveDatagram = new byte[1054];
System.out.println("Server Start");
try
{
while (true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveDatagram, receiveDatagram.length);
datagramSocket.receive(receivePacket);
//System.out.println("len" + receivePacket.getLength());
String receive = new String(receivePacket.getData());
System.out.println(receive.trim() + " received...");
//////// Do it what you want here //////////
//////// done //////////////////////////////
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String msgClient = "Hola Mundo";
System.arraycopy(msgClient.getBytes(), 0, sendDatagram, 0, msgClient.getBytes().length);
DatagramPacket sendPacket = new DatagramPacket(sendDatagram, sendDatagram.length, IPAddress, port);
datagramSocket.send(sendPacket);
}
}
finally
{
datagramSocket.close();
}
}
}
Then, the udp client can do what you are supposed to do.
package justtest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPClient {
public static void main(String[] args) throws IOException {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
InetAddress ipServer = InetAddress.getByName("localhost");
DatagramSocket datagramSocket = null;
DatagramSocket datagramSocketA = null;
DatagramSocket datagramSocketB = null;
byte[] sendDatagram = new byte[1054];
byte[] sendDatagramB = new byte[1055];
byte[] sendDatagramC = new byte[1056];
byte[] receiveDatagram = new byte[1054];
byte[] receiveDatagramB = new byte[1055];
byte[] receiveDatagramC = new byte[1056];
while (true)
{
System.out.println();
System.out.println("Ingrese X");
String msgA = input.readLine();
//sendDatagram = (msgA.getBytes());
System.arraycopy(msgA.getBytes(), 0, sendDatagram, 0, msgA.getBytes().length);
DatagramPacket sendPacket = new DatagramPacket(sendDatagram, sendDatagram.length, ipServer, 6667);
DatagramPacket recvPacket = new DatagramPacket(sendDatagram, receiveDatagram.length, ipServer, 6667);
datagramSocket = new DatagramSocket();
datagramSocket.send(sendPacket);
datagramSocket.receive(recvPacket);
System.out.printf("Send...[%s]/ recv...[%s]", new String(sendDatagram).trim(), new String(recvPacket.getData()).trim());
System.out.println();
System.out.println("Ingrese B");
String msgB = input.readLine();
//sendDatagramB = (msgB.getBytes());
System.arraycopy(msgB.getBytes(), 0, sendDatagramB, 0, msgB.getBytes().length);
DatagramPacket sendPacketB = new DatagramPacket(sendDatagramB, sendDatagramB.length, ipServer, 6667);
DatagramPacket recvPacketB = new DatagramPacket(receiveDatagramB, receiveDatagramB.length, ipServer, 6667);
datagramSocketA = new DatagramSocket();
datagramSocketA.send(sendPacketB);
datagramSocketA.receive(recvPacketB);
System.out.printf("Send...[%s]/ recv...[%s]", new String(sendDatagramB).trim(), new String(recvPacketB.getData()).trim());
System.out.println();
System.out.println("Ingrese C");
String msgC = input.readLine();
//sendDatagramC = (msgC.getBytes());
System.arraycopy(msgC.getBytes(), 0, sendDatagramC, 0, msgC.getBytes().length);
DatagramPacket sendPacketC = new DatagramPacket(sendDatagramC, sendDatagramC.length, ipServer, 6667);
DatagramPacket recvPacketC = new DatagramPacket(receiveDatagramC, receiveDatagramC.length, ipServer, 6667);
datagramSocketB = new DatagramSocket();
datagramSocketB.send(sendPacketC);
datagramSocketB.receive(recvPacketC);
System.out.printf("Send...[%s]/ recv...[%s]", new String(sendDatagramC).trim(), new String(recvPacketC.getData()).trim());
datagramSocket.close();
datagramSocketA.close();
datagramSocketB.close();
}
}
}
I think it is important what you will exactly do with the code.
Good luck.

Java UDP client not receiving from server(simple client server udp code)

I am a newbie in java networking , i made a client-server udp program. The server side is working fine but the client side is not receiving anything from server . Please correct the mistake.The server side is fully running but the client side is not working till its end . Any help would be great.
public class Client {
public static void main (String args[]) throws Exception {
DatagramSocket s = new DatagramSocket();
String msg = "Hello! ,from client. ";
byte[] b = msg.getBytes();
InetAddress ia = InetAddress.getLocalHost();
DatagramPacket dp = new DatagramPacket(b, b.length, ia, 9999);
s.send(dp);
byte[] b2 = new byte[1024]; //byte array
DatagramPacket dip = new DatagramPacket(b2, b2.length);
s.receive(dip);
String str = new String(dip.getData());
System.out.println("From server" + str);
}
}
public class Server {
void run() throws Exception {
DatagramSocket ds = new DatagramSocket(9999);
byte [] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b, b.length);
ds.receive(dp);
String msg = new String(dp.getData());
System.out.println("Message from client:" + msg);
//giving back to client
String str = "HI!, from server.";
byte[] b2 = str.getBytes();
InetAddress ia = InetAddress.getLocalHost();
DatagramPacket dop = new DatagramPacket(b2, b2.length, ia, 9999);
ds.send(dop);
System.out.println("Message sent back");
ds.close();
}
public static void main(String args[]) throws Exception {
Server server = new Server();
server.run();
}
}
Your server is sending all responses to localhost, on port 9999. You need to update the server, so that it reads the address of the sender:
InetAddress ia = dp.getAddress();
int port = dp.getPort();
DatagramPacket dop = new DatagramPacket(b2, b2.length, ia, port);
The error is your server and client run on the same host, so they must listen on different ports like below:
The server
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Server {
void run() throws Exception {
DatagramSocket ds = new DatagramSocket(9999);
byte [] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b, b.length);
ds.receive(dp);
String msg = new String(dp.getData(),0,dp.getLength(),"UTF-8");
System.out.println("Message from client:" + msg);
//giving back to client
String str = "HI!, from server.";
byte[] b2 = str.getBytes();
InetAddress ia = InetAddress.getLocalHost();
DatagramPacket dop = new DatagramPacket(b2, b2.length, ia, 9998);
ds.send(dop);
System.out.println("Message sent back");
ds.close();
}
public static void main(String args[]) throws Exception {
Server server = new Server();
server.run();
}
}
and the client
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Client {
public static void main (String args[]) throws Exception {
DatagramSocket s = new DatagramSocket(9998);
String msg = "Hello! ,from client. ";
byte[] b = msg.getBytes();
InetAddress ia = InetAddress.getLocalHost();
DatagramPacket dp = new DatagramPacket(b, b.length, ia, 9999);
s.send(dp);
byte[] b2 = new byte[1024]; //byte array
DatagramPacket dip = new DatagramPacket(b2, b2.length);
s.receive(dip);
String str = new String(dip.getData(),0,dip.getLength(),"UTF-8");
System.out.println("From server" + str);
}
}

Java - creating threads for different tasks

public class server implements Runnable {
private static final int initialize_server_Port = 8080 ;
private static final int store_server_Port = 8181;
private static final int search_server_Port = 8282;
private static String tname ;
private static InetAddress address ;
protected static Hashtable<String , InetAddress> file_location = new Hashtable<String ,InetAddress>();
server(String tname){
this.tname = tname ;
}
public void run(){
try{
if("storeRecords".equals(tname))
storeRecord();}catch(IOException e ){
System.out.println("error: unable to create store socket");
}
try{
if("searchRecords".equals(tname))
searchRecord();}catch(IOException e){
System.out.println(e);
}
// if("search".equals(tname))
// searchRecord();
}
public void start(){
Thread thread = new Thread(this , tname );
thread.start();
}
public static void storeRecord() throws IOException{
System.out.println("store out");
DatagramSocket serverSocket = new DatagramSocket(store_server_Port);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while(true){
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String file = new String( receivePacket.getData());
file = file.trim();
System.out.println("RECEIVED: " + file);
InetAddress IPAddress = receivePacket.getAddress();
address = IPAddress;
int port = receivePacket.getPort();
System.out.println(file);
file_location.put(file , IPAddress);
String confirmation= "Successfully uploaded";
sendData = confirmation.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
public static void searchRecord() throws IOException{
System.out.println("search out");
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
DatagramSocket serverSocket = new DatagramSocket(search_server_Port);
while(true){
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String file = new String( receivePacket.getData());
file = file.trim();
System.out.println("RECEIVED: " + file);
InetAddress IPAddress = receivePacket.getAddress();
address = IPAddress;
int port = receivePacket.getPort();
boolean found = file_location.containsKey(file);
if(found == true ){
InetAddress query = file_location.get(file);
String confirmation= "found";
sendData = confirmation.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);}
else if (found != true){
String confirmation= "404";
sendData = confirmation.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
}
protected static String server_IP ;
public static void main(String[] args) throws IOException {
server storeThread = new server("storeRecords"); //**************
storeThread.start();
server searchThread = new server("searchRecords");
searchThread.start(); //*********************************
// PrintWriter pw = null ;
//Socket socket = null ;
try {
InetAddress iAddress = InetAddress.getLocalHost();
server_IP = iAddress.getHostAddress();
System.out.println("Server IP address : " +server_IP);
} catch (UnknownHostException e) {
}
DatagramSocket serverSocket = new DatagramSocket(initialize_server_Port);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String confirmation= "Successfully initialized";
sendData = confirmation.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
}
So right now the output is
search out
search out
what im trying to do is create three threads, one thread running the main, 2nd thread running storeRecord which should printout Store out
and 3rd running searchRecord ,
what am i doing wrong here?
In your code, tname is a static variable, hence, shared by all instances of server. It is assigned twice in two calls to the constructor. Making it an instance variable (i.e., removing the static) should do what you want.

UDP Sockets send and receive

I am trying to implement a UDP client server. The client is sending 1032 bytes using the rdt_send function but the server receives this packet only after the client is executed twice.
Here is the code for :
rdt_send:
public void rdt_send(byte[] buffer, Integer mss, DatagramSocket s,Integer seqNum) throws IOException
{
int i,j,k;
byte[] seq_num = new byte[4];
byte[] seqnum_temp = new byte[4];
byte [] checksum = new byte[2];
byte [] udp_field = new BigInteger("0101010101010101",2).toByteArray();
Integer checksum_value = (int)calculateChecksum(buffer);
checksum = new BigInteger(checksum_value.toString(), 10).toByteArray();
seqnum_temp = new BigInteger(seqNum.toString(),10).toByteArray();
System.out.println(checksum_value);
Integer length_temp = seqnum_temp.length;
if (seqnum_temp.length<4)
{
Integer append = 4 -seqnum_temp.length;
for (i=0;i<append;i++)
{
seq_num[i] = 0;
}
for (j = append, k=0 ; j<4 && k<length_temp ; j++,k++)
{
seq_num[j] = seqnum_temp[k];
}
System.out.println(seq_num[0]);
}
byte[] finalSend = new byte[mss+8];
for (i=0;i<4;i++)
{
finalSend[i] = seq_num[i];
}
for (i=4,k=0;i<6 && k<2;i++,k++)
{
finalSend[i] = checksum[k];
}
for (i=6,k=0;i<8 && k<2 ;i++,k++)
{
finalSend[i] = udp_field[k];
}
for (i=8,k=0;i<finalSend.length && k< buffer.length;i++,k++)
{
finalSend[i] = buffer[k];
}
for (i=0;i<finalSend.length;i++)
{
System.out.println(finalSend[i]);
}
System.out.println("Got to final sending stage");
DatagramPacket p = new DatagramPacket (finalSend,finalSend.length,InetAddress.getLocalHost(),7771);
s.send(p);
System.out.println("Sent datagram");
}
client :
package simpleFTP;
public class SimpleFTPClient {
public static void main(String args[]) throws IOException{
Integer seq_num =512;
Utils u = new Utils();
DatagramSocket d = new DatagramSocket();
File f =new File("C:/Users/amoolp/Desktop/client3/3333.txt");
FileInputStream fs = new FileInputStream(f);
byte[] bytesRead = new byte[1024];
fs.read(bytesRead,0,1024);
//DatagramPacket p = new DatagramPacket (bytesRead,bytesRead.length,InetAddress.getLocalHost(),7771);
// d.send(p);
u.rdt_send(bytesRead,1024,d,seq_num);
}
}
Server :
public class Server {
public static void main (String args[]) throws IOException
{
DatagramSocket dg = new DatagramSocket (7771);
byte[] buf = new byte[1032];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
System.out.println("Waiting to receive packet");
dg.receive(packet);
System.out.println("Received packet");
for (int i=0; i<buf.length ; i++)
{
System.out.println(buf[i]);
}
}
}
Any ideas as to why this is happening?
It's due to the buffer. flush() the socket after sending a packet.

Categories

Resources