Hey guys, i've been searching for some info on sockets programming for a few hours right now and still can't understand how to solve a problem i have.
I've been asked to do the following :
The server receives an UDP datagram at the port 8080, sent from a client, in the datagram the client sends an array of chars that represents a number(9090)
The server will create a new socket, establish a TCP connection with the client at the port
9090.
Through the tcp connection, the server will read the a name, sent by the client.
We're asked to write a client able to do those tasks in C, the server is already done and is found in a .jar file
The program should run like this : ./client SERVER_NAME
and the server: java -jar server.jar
i got as far as this goes...with a think it covers the first part(sending the udp package) but not quite sure how to follow:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "8080" // the port users will be connecting to
int main(int argc, char *argv[])
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
if (argc != 2) {
fprintf(stderr,"usage: talker hostname\n");
exit(1);
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
int num = 9090;
num = htonl(num);
if ((numbytes = sendto(sockfd, num, sizeof(num), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto");
exit(1);
}
Does the java server provide any feedback you can use to verify the your UDP thus far? If so, I would verify and proceed as follows..
Setup a separate socket to make the TCP connection. There are many resources on the Internet showing how to do that (Google 'c tcp client example'). Since UDP is an unreliable best-effort protocol you will want to have a method for retrying the connection. One solution might be to loop, sending the UDP datagram and trying the TCP connection on the other socket until the connection is made (or some other time limit or maximum retry limit is reached).
// setup TCP socket to connect to your chosen port 'num'...
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
// handle error
struct sockaddr_in tcpServAddr;
memset(&tcpServAddr, 0, sizeof(tcpServAddr));
tcpServAddr.sin_family = AF_INET;
tcpServAddr.sin_addr.s_addr = inet_addr(<insert server ip here>);
tcpServAddr.sin_port = htons(num);
const int iMaxTries = 10;
int iTryCount = 0;
bool bConnected = false;
while(!bConnected && (iTryCount < iMaxTries)) {
// using your bock from above:
if ((numbytes = sendto(sockfd, num, sizeof(num), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto"); // may want to output strerr(errno) for more information
break; // something is wrong if we can't send UDP. bail and figure that out
}
++iTryCount;
// try the TCP connection on the target port
if (connect(tcpSockFd, (struct sockaddr *) &tcpServAddr, sizeof(tcpServAddr)) == 0) {
bConnected = true;
} else {
// report error
}
}
if (bConnected) {
// send(...) name on tcpSockFd
}
// cleanup sockets
None of the above is tested, but hopefully it gives you some general direction.
Related
I'm creating a server app in C++ and client app in Java. I want to exchange 32 bit integer between them.
And I've got a trouble, because when I'm trying send something from Java's client, I get a random answer in C++ server (e.g. I've send '0' and one time I've got a one number, another time I've got different number. I've read about Little and Big Endian coding, but I think it is another issue, because sending '0' generate a huge value different from 0.
Java Client:
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Main {
public static void main(String[] args) throws Exception{
Socket socket = new
Socket(InetAddress.getByName("127.0.0.1"),10000);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeInt(0);
}
}
C++ Server:
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
#include <iostream>
using namespace std;
int main(){
int port = 10000;
string ip_addr = "127.0.0.1";
int domain = AF_INET;
int type = SOCK_STREAM;
int protocol = 0;
int stopCondition = 0xFFFFFFFF;
int socketHandle;
struct sockaddr_in address;
int clientSocketHandle;
struct sockaddr_in clientAddress;
size_t clientAddressSize;
int buffer;
if((socketHandle=socket(domain,type,protocol))<0)
cout<<strerror(errno);
address.sin_family = domain;
inet_pton(domain,ip_addr.c_str(),&address.sin_addr);
address.sin_port=htons(port);
if((bind(socketHandle,(struct sockaddr *)&address,sizeof(address)))<0)
cout<<strerror(errno);
if (listen(socketHandle, 1) < 0)
cout << strerror(errno);
if ((clientSocketHandle = accept(socketHandle, (struct sockaddr *) &clientAddress, (socklen_t *) &clientAddressSize)) < 0)
cout << strerror(errno);
do {
if (recv(clientSocketHandle, &buffer, sizeof(int), 0) > 0)
cout<<buffer<<endl;
} while (buffer != stopCondition);
if(shutdown(clientSocketHandle,SHUT_RDWR)<0)
cout<<strerror(errno);
if(shutdown(socketHandle,SHUT_RDWR)<0)
cout<<strerror(errno);
return 0;
}
How should I implement my client in Java to work properly with my C++ server?
Java server socket
In the following code:
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KnockKnockServer.java
import java.net.*;
import java.io.*;
public class KnockKnockServer {
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: java KnockKnockServer <port number>");
System.exit(1);
}
int portNumber = Integer.parseInt(args[0]);
try (
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
) {
String inputLine, outputLine;
// Initiate conversation with client
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye."))
break;
}
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
when the server sends its response to the client socket, it writes to the "PrintWriter" "out" using the "println()" method (line 63).
I have tried using the "print()" method instead.
In the "println()" case, the client socket receives the message properly.
In the "print()" case, the client socket doesn't receive anything.
Is this normal?
Is it required to send an EOF, a CR LF (in my case) (10 and 13 ASCII characters) at the end of the message?
Is it documented somewhere?
Winsock
In the following code:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737591%28v=vs.85%29.aspx
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char *sendbuf = "this is a test";
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Validate the parameters
if (argc != 2) {
printf("usage: %s server-name\n", argv[0]);
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
// Send an initial buffer
iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %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 with error: %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 with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
the "send()" method is used.
Does it implicitly send an EOF (a CR LF sequence for example) to the server socket at the end of the message passed as an argument?
Is it documented somewhere?
Is it part of the socket implementation?
Note that, I am not adding a EOF (CR LF for example) at the end of the message.
I'm ending the message with a trailing '\0' character.
When a "message" (an array of characters) is sent from a socket endpoint to another socket endpoint, does the message have to be ended with some kind of EOF? It appears to me now that it doesn't.
There is no general need to send an EOF sign in java socket communication, BUT
if your client uses InputStream.readLine() to read the servers answer, than this is normal, because
readLine() blocks until a line has been completely read (until \n \r or \r\n found) or the socket is closed by the server.
But in this example, the socket is not closed by the server, because the server is waiting for the clients answer and if the client is waiting for the end of line, you have a deadlock.
when the server sends its response to the client socket, it writes to the "PrintWriter" "out" using the "println()" method
PrintWriter is line buffered. See the Javadoc.
I have tried using the "print()" method instead.
If you don't write a line it won't flush. Call flush() afterwards. But you shouldn't use PrintWriter over a network, as it swallows exceptions you need to know about. Use BufferedWriter.
In the "println()" case, the client socket receives the message properly.
Because it's line-buffered, so there was an auto-flush.
In the "print()" case, the client socket doesn't receive anything.
Because it's line-buffered so there wasn't an auto-flush.
Is this normal?
Yes.
Is it required to send an EOF, a CR LF (in my case) (10 and 13 ASCII characters) at the end of the message?
No.
Is it documented somewhere?
Yes, in the Javadoc for PrintWriter.
I have two apps, one written in Java that sends string, it looks like this:
import java.io.*;
import java.net.*;
public class Gniazdo{
public static void main(String[] args) throws IOException {
DataOutputStream dataOutputStream = null;
Socket socket = null;
String mes = "Test message";
try {
socket = new Socket("192.168.1.116", 4014);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeChars(mes);
} catch (UnknownHostException e) {
System.err.print(e);
} finally {
if(socket != null) {
socket.close();
}
if(dataOutputStream != null) {
dataOutputStream.close();
}
}
}
}
and second one is written in C and runs on Raspberry Pi, that should receive string :
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
int main(void) {
unsigned int port;
char bufor[1024];
int gniazdo, gniazdo2;
struct sockaddr_in adr, nadawca;
socklen_t dl;
printf("Enter port to listen : ");
scanf("%u", &port);
gniazdo = socket(AF_INET, SOCK_STREAM, 0);
adr.sin_family = AF_INET;
adr.sin_port = htons(port);
adr.sin_addr.s_addr = INADDR_ANY;
if (bind(gniazdo, (struct sockaddr*) &adr,
sizeof(adr)) < 0) {
printf("Bind failed.\n");
return 1;
}
if (listen(gniazdo, 10) < 0) {
printf("Listen failed.\n");
return 1;
}
printf("Waiting for connection ...\n");
while (gniazdo2 = accept(gniazdo,
(struct sockaddr*) &nadawca,
&dl)
)
{
// memset(bufor, 0, 1024);
recv(gniazdo2, bufor, 1024, 0);
printf("message from %s: %s\n", inet_ntoa(nadawca.sin_addr), bufor);
close(gniazdo2);
}
close(gniazdo);
}
and my output is:
Enter port to listen : 4014
Waiting for connection ...
message from 192.168.1.103:
message from 192.168.1.103:
message from 192.168.1.103:
message from 192.168.1.103:
Please could anyone tell me whats wrong?
Why i don't receive the message?
I even checked packets outgoing from my computer with Wireshark and they contains my message, but still don't know where I made mistake
1) Try calling writeBytes(String s) on the DataOutputStream.
2) Try calling flush on the DataOutputStream
(even though close should be calling flush anyway).
3) Try using PrintWriter to send the String
See
http://docs.oracle.com/javase/6/docs/api/java/io/PrintWriter.html#PrintWriter%28java.io.OutputStream,%20boolean%29
and this method in particular
http://docs.oracle.com/javase/6/docs/api/java/io/PrintWriter.html#write%28java.lang.String%29
4) Also, I think you should swap these two
if(socket != null) {
socket.close();
}
if(dataOutputStream != null) {
dataOutputStream.close();
}
printf is looking at 'bufor' as a char (8-bit), but java will write 16-bit UTF-16 characters. The first byte of the first character is 0. printf sees the 0 and thinks it's the end of the string. Try formatting the string to UTF-8 when you write it to the socket or reading it and printing it as a wchar.
I have a simple server written in Java, that just sends an Integer to a connected client. I have a client written in C, that connects to the server and prints out the received Integer.
My problem is that the result varies. About half of the times executing the client I get the correct result (234), but other times I get 8323072.
This is the server:
class TCPServer {
public static void main(String args[]) throws Exception {
ServerSocket welcomeSocket = new ServerSocket(6789);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
System.out.println("welcomeSocket.accept() called");
DataInputStream inFromClient = new DataInputStream(connectionSocket.getInputStream());
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
outToClient.writeInt(234);
}
}
}
And this is the client:
int main(int argc, char *argv[])
{
if(argc != 4){
printUsage();
return;
}
char* serverIP = argv[1];
char* serverPortC = argv[2];
char* integerToSendC = argv[3];
int serverPort = atoi(serverPortC);
int integerToSend = atoi(integerToSendC);
int socketDesc = socket(AF_INET, SOCK_STREAM, 0);
if(socketDesc < 0) {
printf("Error when creating socket\n");
return;
}
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(serverPort);
inet_pton(AF_INET, serverIP, &serverAddr.sin_addr);
int connection = connect(socketDesc, (struct sockaddr*) &serverAddr, sizeof serverAddr);
if(connection < 0) {
printf("Error when establishing connection\n");
return;
}
char intBuffer[4];
if(recv(socketDesc, intBuffer, sizeof intBuffer, 0) == -1){
printf("Error while receiving Integer\n");
}
int receivedInt = ntohl(*((int *) &intBuffer));
printf("Received int: %d\n", receivedInt);
close(socketDesc);
}
Thanks in advance for any help!
Edit:
So in the end I did something like this, just for anybody who has the same problem:
while(receivedBytes < 4){
int readBytes = read(receiverSocket, &intBuffer, (sizeof intBuffer) - receivedBytes, receivedBytes);
receivedInteger += (intBuffer << (8*receivedBytes));
receivedBytes += readBytes;
}
Can you be sure you have received sizeof intBuffer bytes on the client side? No you can not, as recv() might return less bytes then requested.
Mod you code to loop around recv() as long as less bytes then requested have been received and no error occurred.
Note that recv()ing 0 bytes indicates the connection had been closed by the other side.
Also make sure the server side sends in network byte order.
Also^2: It is good idea to initialise variables (intBuffer here), at least during the development phase, will say: prior to the tuning phase.
Your problem could be because of the sub-boundaries of the various data types.
In Java, 4 bytes are assigned to int and 2 bytes for a short.
In C, 4 bytes are for long and 2 bytes for int.
This means Java int -> C long and Java short -> C int.
Now it depends on where your priorities lie.
If you want to perform an intense mathematical calculation in Java and send the result over socket to C, I recommend you do Java int -> C long or
If you want to just send small numbers and have the intense calculation done in C, do the Java short -> C int conversion.
Hope that helped.
This question may sound basic one . Are there any functions in c or Java where I can get the socket details like , port , address , buffer size using only socket identifier ?
Some minimal information available with me is posted below.
I don't know much of Java. But as far as 'C' is concerned, you can use the getsockopt function to get the buffer sizes (send buffer and recv buffer) of the socket.
It appears getsockname helps you in getting the ip & port to which the socket is bound to.
In c in the function accept:
csock = accept(sock, (struct sockaddr*)&csin, &recsize);
sock is the socket server(int)
csock is the socket client (int)
recsize is the size
csin is a struct with client's details
csin.sin_addr is the client's address
csin.sin_port is the client's port
From a socket ID try this:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
f()
{
int s;
struct sockaddr_in sa;
int sa_len;
.
.
.
/* We must put the length in a variable. */
sa_len = sizeof(sa);
/* Ask getsockname to fill in this socket's local */
/* address. */
if (getsockname(s, &sa, &sa_len) == -1) {
perror("getsockname() failed");
return -1;
}
/* Print it. The IP address is often zero beacuase */
/* sockets are seldom bound to a specific local */
/* interface. */
printf("Local IP address is: %s\n", inet_ntoa(sa.sin_add r));
printf("Local port is: %d\n", (int) ntohs(sa.sin_port));
.
.
.
}