I have a ServerSocketChannel and once this channel accepts a connection I want to "transfer" or "pass" it to a SocketChannel. I have tried, once I have accepted the connection, to simply do a socketchannel.bind(ServerSocketChannel.socket.getLocalSocketAddress) but I get an exception that says "Address already in use". Which makes sense so I have tried to save the socket address in a variable, close the ServerSocketChannel, and then attempt to bind it with the variable but it still complains about already being in use.
//Accept the connection
ServerSocketChannel.accept();
//Save the address and close the connection
address = ServerSocketChannel.socket().getLocalSocketAddress();
ServerSocketChannel.close();
//Bind the address to another channel
SocketChannel.bind(address);//Here is where I get the exception
This is how my solution looks right now(except for the variable names but you get the idea). The reason I can't just accept it with that channel is because it's used for another purpose once this connection has been established, so I need to have dedicated ServerSocketChannel opened just for accepting connections which are then passed to the SocketChannel.
I just solved my problem. I overlooked something simple and tried a longer way instead.
SocketChannel = ServerSocketChannel.accept();
Is what I was looking for all along.
Related
This accept() method return a tuple with a new socket and an address but why do i need a new socket if i already have one, so why don't use it?
import socket
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
conn, addr = sock.accept()
print 'connected:', addr
while True:
data = conn.recv(1024)
if not data:
break
conn.send(data.upper())
conn.close()
ps: When i program sockets in Java, i don't really have this kind of accepting stuff and i only need one socket per client and one per server, which makes sense.
You have one listening socket active while the server is running and one new connected socket for each accepted connection which is active until the connection is closed.
Seems like you haven't implemented TCP in Java before.
The example you are providing with, uses a default AF_INET and SOCK_STREAM which by default is TCP:
socket.socket([family[, type[, proto]]])
Create a new socket using the given address family, socket type and protocol number. The address family should be AF_INET (the default), AF_INET6 or AF_UNIX. The socket type should be SOCK_STREAM (the default), SOCK_DGRAM or perhaps one of the other SOCK_ constants. The protocol number is usually zero and may be omitted in that case.
If you were implemented SOCK_DGRAM which is UDP, you wouldn't need to be using sock.accept()
I have a java.nio.channels.ServerSocketChannel which I initialised as follows:
while(true)
{
ServerSocketChannel channel = ServerSocketChannel.open();
InetSocketAddress serverSocket = new InetSocketAddress(host,port);
channel.bind(serverSocket);
SocketChannel ch = channel.accept();
// Later on when I have read off data from a client, I want to shut this
// connection down and restart listening.
channel.socket().close(); //Just trying to close the associated socket
// too because earlier approaches failed
channel.close();
}
When I send the first message from client it is successfully delivered to server and the client program exits. Then trouble begins. When I initialise the client again and try to
establish at the same port and address of the server as I did the first time, I get a
java.net.BindException: Address already in use: connect
exception even though I closed the associated channel/socket.
I have been renewing the ServerSocketChannel and InetSocketAddressobjects because as my client instance has to shut down after a write, I have to disengage that channel and since I cannot reuse a channel after it has been closed, I have to make a new object everytime. My theory is since the channel reference is reassigned each time, the orphaned object becomes GC meat, but since the close() method apparently is not working properly, the channel is still alive and until GC collects it my port will be hogged.
Nevertheless I tried keeping the initialisation of ServerSocketChannel and InetSocketAddress objects before the while loop, but this did not help, and the same exception occurred after the first write, as before.
ServerSocketChannel channel = ServerSocketChannel.open();
InetSocketAddress serverSocket = new InetSocketAddress(host,port);
channel.bind(serverSocket);
while (true)
{
SocketChannel ch = channel.accept();
//read from a client
}
For clarity , here is how I connect from the client:
SocketChannel ch=SocketChannel.open();
ch.bind(new InetSocketAddress("localhost", 8077));
InetSocketAddress address=new InetSocketAddress("localhost",8079);
//the address and port of the server
System.out.print(ch.connect(address));
ByteBuffer buf=ByteBuffer.allocate(48);
buf.clear();
buf.put("Hellooooooooooooooooooooooooo".getBytes());
buf.flip();
while(buf.hasRemaining()) {
ch.write(buf);
}
ch.close();
It looks like you're confusing client and server. Normally, server starts only once and binds to s port. Usually, there's no need to close there anything as the port gets freed when the program exits. Obviously, you must close the Sockets obtained by ServerSocket.accept(), but that's another story.
I guess you've got confused by your variable names (just like it happened to me as I started with this). Try to call all things according to their type, here was Hungarian really helpful for me.
The code I wrote for testing this is long, stupid, and boring. But it seems to work.
It may also be helpful to do:
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
Search for information about this option to learn more.
do ch.close() as well to GC the client socket.
I'm trying to receive UDP data broadcast by PlayCap to network address 192.168.103.255 port 3000 in Java, but I'm having trouble setting things up. Here's what I have:
DatagramSocket socket = new DatagramSocket();
InetSocketAddress address = new InetSocketAddress("192.168.103.255", 3000);
socket.bind(address);
I'm getting "java.net.SocketException: already bound" from the bind call. I'm pretty inexperienced with networking, so I may be doing something way wrong here. Any help is appreciated.
Here is the stacktrace:
java.net.SocketException: already bound
at java.net.DatagramSocket.bind(Unknown Source)
at runner.main(runner.java:16)
I dont want to revive and old thread but i don't think the answer to this question is correct. I faced the same issue when i used the similar code to create a DatagramSocket.
DatagramSocket socket = new DatagramSocket();
socket.setReuseAddress(true);
socket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), 5566));
This results in a SocketException
Exception in thread "main" java.net.SocketException: already bound
at java.net.DatagramSocket.bind(DatagramSocket.java:376)
at testapplication.TestApplication.main(TestApplication.java:25)
Java Result: 1
Not because there is another process occupying the same port but i have created an already BOUND datagram socket when i use the default constructor.
new DatagramSocket()
According to javadoc:
DatagramSocket()
Constructs a datagram socket and binds it to any available port on the
local host machine.
So the reason for the exception is you are trying to bind an already bound socket. To make it work you need to create an unbond socket with below constructor
DatagramSocket socket = new DatagramSocket(null);
InetSocketAddress address = new InetSocketAddress("192.168.103.255", 3000);
socket.bind(address);
Hope this helps...
Do netstat -a -o -n and from this you can find that either this port is already bind or not(even from this you can get all the bound ports).If yes , then try any other port :)
Most probably your application is running twice. Or you might be executing the same code twice. Even the same application may fail when binding twice.
Happens a lot for beginners that they didn't shut down their previous attempt (happened to me, too), and then their port is already in use. Make sure to add proper exception handling, e.g. by popping up a message "Port already in use."
Note that for listening you usually will bind a port only, without an explicit address (you might need to use "0.0.0.0" for this). Then you can receive both broadcast and unicast.
The code I use for listening to broadcasts is simply:
DatagramSocket s = new DatagramSocket();
s.bind(new InetSocketAddress(port))
Note that I'm not binding to a particular address, but only to a port.
Check the port 3000 it may be already used by another application. Try using a different port.
I have a serversocket running on a port say 7761 in my server with ip say 10.2.110.43
now there are many client that run on different servers waiting for connection on port 7761, and write data in ascii format to that port.
I want the serversocket to verify the client-ipadress and then accept connection from client.
Is there a way to do that?
If you don't mind running under a SecurityManager and the list of IP addresses is static, you can accomplish this via the security.policy file. Just grant SocketPermission"accept" to only those IP addresses you want to accept connections from. However doing it in code or the firewall as suggested in another answers is probably preferable.
We see in the following code, we can't check address of counterparts before accept() but after:
Socket client = serverSocket.accept()
if( acceptedClients.contains( client.getInetAddress()) {
...
}
else {
client.close();
}
With acceptedClients a collection of well known InetAddress.
If you don't want the connection to reach your Java ServerSocket#accept() unless it comes from a specific IP, you will have to configure your firewall to do this.
You can always validate the IP address after the connection is established and immediately close it if it's not from the right IP.
I have a socket running, using selectors. I am trying to check to see if my socket is connected to the server or not.
Boolean connected = _channel.isConnected();
and it always returns true. I turned off Airport (internet connection) on my computer, and when i check to see if the socket is connected or not, it still returns true.
Any idea why?
I try to write data to the server every 3 seconds, and it still doesn't change the state of my socket to disconnected.
Usually if you turn off OS level networking, writes to socket should throw exceptions, so you know the connection is broken.
However more generally, we cann't be sure if a packet is delivered. In java (probably C too), there is no way to check if a packet is ACK'ed.
Even if we can check TCP ACKs, it doesn't guarantee that the server received or processed the packet. It only means that the target machine received the packet and buffered it in memory. Many things can go wrong after that.
So if you really want to sure, you can't rely on transport protocol. You must have application level ACK, that is, the server application writes back an ACK message after it received and processed a message from client.
From client point of view, it writes a message to server, then tries to read ACK from server. If it gets it, it can be certain that its message is received and processed. If it fails to get ACK, well, it has no idea what has happened. Empirically, most likely TCP failed. Next possiblity is that server crashed. It's also possible that everything went OK, except the ACK couldn't reach the client.
A socket channel can be connected by invoking its connect method; once connected, a socket channel remains connected until it is closed.
The channel is not closed when the server is not available anymore, due to a broken physical connection or a server failure. So once a connection has been established, isConnected() will be returning true until you close the channel on your side.
If you want to check, if the server is still available, send a byte to the sockets outputstream. If you get an Exception, then the server is unavailable (connection lost).
Edit
for EJP - some code to test and reconsider your comment and answer:
public class ChannelTest {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket google = new Socket(InetAddress.getByName("www.google.com"), 80);
SocketChannel channel = SocketChannel.open(google.getRemoteSocketAddress());
System.out.println(channel.isConnected());
channel.close();
System.out.println(channel.isConnected());
}
}
Output on my machine is
true
false
isConnected() tells you whether you have connected the channel object, which you have, and it's not specified to return false after you close it, although apparently it does: see Andreas's answer. It's not there to tell you whether the underlying connection is still there. You can only tell that by using it: -1 from a read, or an exception, tells you that.