This is my first time socket programming and have a question about send and recv. I'm sending a file from server to client which works fine. But, when I want to continue my program with more send() and recv() calls (the commented code at the end of client and server), the client receives this data and writes it to newfile.txt.
So, my question is, how do I call send() from the server to only send data from test.txt, and then recv() on the client to only receive and write data from test.txt to newfile.txt? After this, I would want to continue with my program with more send() and recv() calls which dont get mixed up with the file transfer code.
Client:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int port = 8001;
int client_socket;
struct sockaddr_in server_addr;
int connect_status;
client_socket = socket(AF_INET, SOCK_STREAM, 0); //SOCK_STREAM for TCP
if (client_socket < 0)
{
printf("Error creating socket\n");
exit(1);
}
printf("Socket created\n");
//address for socket to connect to
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port); //8001 arbitrary port
server_addr.sin_addr.s_addr = INADDR_ANY;
//connect to address of socket
connect_status = connect(client_socket, (struct sockaddr *) &server_addr, sizeof(server_addr));
if(connect_status == -1)
{
printf("Error connecting to server\n");
exit(1);
}
printf("Connected to Server\n");
FILE* fp = fopen( "newfile.txt", "w");
char data[512];
int b;
while((b=recv(client_socket, data, 512,0))>0){
fwrite(data, 1, b, fp);
}
fclose(fp);
//recv(client_socket, data, 512,0);
//printf("client buffer: %s\n", data);
close(client_socket);
return 0;
}
Server:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int port = 8001;
int server_socket;
struct sockaddr_in server_addr;
int client_socket, client_addr;
int bind_status, listen_status;
server_socket = socket(AF_INET, SOCK_STREAM, 0); //SOCK_STREAM for TCP
if (server_socket < 0)
{
printf("Error creating socket\n");
exit(1);
}
printf("Socket created\n");
//address for socket to connect to
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
//bind socket to the IP and port
bind_status = bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (bind_status < 0)
{
printf("Error binding to socket\n");
exit(1);
}
printf("Socket binded\n");
//listen for client connections
listen_status = listen(server_socket, 10);
if (listen_status == -1)
{
printf("Error listening to socket\n");
exit(1);
}
printf("Listening\n");
//accept client connection
socklen_t addr_len;
addr_len = sizeof(client_socket);
client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &addr_len);
FILE *fp = fopen("test.txt", "r");
char data[512];
int b;
while((b = fread(data, 1, 512, fp))>0){
send(client_socket, data, b, 0);
}
fclose(fp);
// strcpy(data,"test message");
//printf("server buffer: %s\n", data);
//send(client_socket, data, 512, 0);
close(server_socket);
return 0;
}
You need some way to indicate the server that you have finished sending a file, and now you want to send another thing.
While the socket abstraction seems to show you that the recv and send calls are somehow synchronized, this means that the data you send from the client in one call to send is recv'd in the server with exactly one recv, that is not true, due fundamentally to how the sockets are implemented (the client tcp can decide to split your transfer in several packets, and the unattending of the server can make all those packets to buffer n the receiver before the server receives part of them in one call to recve and others in the text call.
The only thing sure is that a byte that has been sent before, is receive before, and no repeated or missing bytes in between. But the number of bytes received at some recve call is dictated only by the amount of buffered data that one side of the connection has.
This means that, for telling the server that you are finished with your file and some other thing is to be sent, you must do something that allows the server to recognize that the data has ended and more data on a different thing is about to come.
There are several approaches here... you can send an inband sequence (some control sequence) that, wen read in the other side, will be recognized as the end of a block of data and the beginning of the next. Some systems use a packet encoding that simply prepends each block with a number of bytes to follow, and an empty packet (e.g. a single number 0, meaning 0 bytes to follow) can represent this sequence. Another way, can be to use a specific sequence you know is improbable to occur in the data (e.g. \n.\m, two newlines with one dot interspersed ---this has been used many times in unix's ed editor, for example, or the post office protocol uses it.) and if it is the case that such a sequence happens to be in the file, just double the dot, to indicate that it is not the separator sequence. And both ends must agree on this (so called) protocol.
Other mechanisms are valid, you can close the connection and use another socket for a new data exchange.... for example, FTP protocol uses this approach by using one control connection for FTP commands, while using other connections for data transfers.
I have not included code because there are plenty of examples in the literature. Try to get access to the book "Unix Network Programming" of Richard W. Stevens. That's a very good reference to get initiated on socket protocols and how to deal with all these things.
Related
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <pthread.h>
#include <arpa/inet.h>
struct sockaddr_in server, acc;
int sock;
int stuff(void) {
char buffer[2000];
recv(sock, buffer, sizeof(buffer), 0);
send(sock, "HTTP/1.1 200 OK\nContent-Type: text/html\n\nHello", sizeof("HTTP/1.1 200 OK\nContent-Type: text/html\n\nHello"), 0);
shutdown(sock, SHUT_RDWR);
return 0;
}
int main(void) {
int size;
sock = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(1111);
if (bind(sock, (struct sockaddr*)&server, sizeof(server)) == -1) {
perror("Error:");
return 1;
}
while (1) {
listen(sock, 5);
sock = accept(sock, (struct sockaddr*)&acc, &size);
printf("accepted\n");
stuff();
close(sock);
}
}
This is meant to be an extremely basic HTTP server.
I don't know what's going wrong, but the connection seems to not end with the client.
Opening this in the browser, it doesn't stop loading and the console is flooded with "accepted" (line 42). No new connections can be accepted.
After your program accepts a connection, it forgets about the socket that listens for new connections, does remember the newly connected socket, does some stuff with that socket, closes it, then tries to accept another connection from the connected socket that it just closed.
There are two problems here:
It's the wrong socket
Even if it was the right socket, it's closed
You create socket number 3 (for example) to wait for new connections. You wait for a connection on socket 3 and the new connection is socket number 4 (for example). Then you do the stuff, then you close socket 4, then you wait for a new connection on socket 4. Do you see the mistake here? Socket 3 is the one that accepts connections.
Since you are not new to programming, you should be able to figure out how to make your program call accept with the right socket.
So I have a device connected to my network card and it sends data to port 11678 and address 192.168.121.1 using IPv4 and UDP. I have checked that the device does actually send to that port and address using IPv4 and UDP by calling tcpdump. However my C socket does not receive any packets. Below I have a minimum non-working example that just runs an infinite loop until one packet is received. It does not receive any packets even though tcpdump does, so I assume something is wrong with my code.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define DEST_ADDR "192.168.121.1"
#define DEST_PORT 11678
#define PACKET_MAXSIZE 1024
int main(int argc, char **argv) {
struct sockaddr_in dest_addr;
bzero(&dest_addr, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
/* create socket */
int fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); // use SOCK_NONBLOCK?
if (fd < 0) {
perror("Could not create socket.");
}
/* bind port and address to socket */
dest_addr.sin_port = htons(DEST_PORT);
inet_aton(DEST_ADDR, &dest_addr.sin_addr);
int rc = bind(fd, (struct sockaddr*) &dest_addr, sizeof(dest_addr));
if (rc != 0) {
perror("Could not bind socket to local address");
}
/* read packets */
void* buf;
posix_memalign(&buf, 4096, 1024);
while (true) {
ssize_t read_size = read(fd, buf, PACKET_MAXSIZE);
printf("%d\n", read_size);
if (read_size > 0) {
break;
}
}
return 0;
}
The read just returns -1 and sets errno to 11 (EAGAIN) in every iteration. Any help is appreciated. Thanks in advance.
If you're on a system that uses iptables, check that you aren't dropping packets. tcpdump will show packets that are incoming before they get to iptables.
Another thing is that you should be using epoll or select to read from the socket in a more controlled way. EAGAIN isn't neccessarily wrong: it just means there's no data. But you're whizzing round that while loop without waiting, so I'd expect lots of EAGAIN's until something actually arrives at the port.
I am learning socket on c. I have a client and a server, when the server closed the socket, the client still able to receive and sent to server two more packages before the send get a SIGPIPE signal. I don't know why. Can anyone help pls~
since the documentation said that if the send and recv have error then they will return -1. But this never happen in my case here.
Client side
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFFERSIZE 255
#define MAXLENG 96
#define true 1
#define false 0
void exitp();
int main(int argc, char *argv[]){
signal(SIGPIPE, exitp);
// Check if the argument is match the requirement
if (argc != 3) {
fprintf(stderr, "Useage Error, should be follow by ip, and port\n" );
exit(1);
}
// Create the socket for the client, if the fd for the socket == -1, it means
// it created fail
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0){
fprintf(stderr, "Create socket failed\n" );
exit(1);
}
int PORT = atoi(argv[2]);
// Set up server argument
struct sockaddr_in server_addr;
memset(&server_addr, '0', sizeof(server_addr)); // addr for bin
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
// ip not vaild
if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) < 1){
fprintf(stderr, "IP address not correct\n" );
exit(1);
}
// create the connection
if (connect(skfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1){ // Connect to server
fprintf(stderr, "Connection Fail\n" );
exit(1);
}
char sentbuff[255], recvbuffer[255], input[255], request[100], concelbuffer[255];
// Send the request to the server
int nn;
int size = send(skfd, request, sizeof(request),0);
while(1){
if (recv(skfd, &recvbuffer,sizeof(recvbuffer),0) == -1){
printf("Server Closed\n");
break;
}
printf("%s",recvbuffer);
fgets(sentbuff, 255, stdin);
nn=send(skfd, &sentbuff, sizeof(sentbuff), 0);
if (nn == -1){
printf("Server Closed\n");
break;
}
}
return 0;
}
void exitp(){
printf("%s\n","Server Closed" );
exit(0);
}
server side I used shutdown and close for the acceptfd
send() just puts the data in the kernel socket buffer, it doesn't wait for the data to be transmitted or the server to acknowledge receipt of it.
You don't get SIGPIPE until the data is transmitted and the server rejects it by sending a RST segment.
It works this way because each direction of a TCP connection is treated independently. When the server closes the socket, it sends a FIN segment. This just tells the client that the server is done sending data, it doesn't mean that the server cannot receive data. There's nothing in the TCP protocol that allows the server to inform the client of this. So the only way to find out that it's not accepting any more data is when the client gets that RST response.
Informing the client that they shouldn't send anything more is usually done in the application protocol, since it's not available in TCP.
I created a TCP client and a server in C and executed it in two terminals. But after changing and compiling the code, I could not get the output. Both server and client keep running and print nothing.
Here is my server code
/* Sample TCP server */
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
int fsize(FILE *fp){
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
return sz;
}
int main(int argc, char**argv)
{
int listenfd,connfd,n, length;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
char* banner = "ack";
char buffer[1000];
/* one socket is dedicated to listening */
listenfd=socket(AF_INET,SOCK_STREAM,0);
/* initialize a sockaddr_in struct with our own address information for binding the socket */
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
/* binding */
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(listenfd,0);
clilen=sizeof(cliaddr);
while(1){
/* accept the client with a different socket. */
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
// the uninitialized cliaddr variable is filled in with the
n = recvfrom(connfd,buffer,1000,0,(struct sockaddr *)&cliaddr,&clilen);//information of the client by recvfrom function
buffer[n] = 0;
sendto(connfd,banner,strlen(banner),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
printf("Received:%s\n",buffer);
FILE *fp = fopen("serverfile.txt", "r");
length = fsize(fp);
printf("%d\n", length);
}
return 0;
}
Here is my client code
/* Sample TCP client */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char**argv)
{
int sockfd,n;
struct sockaddr_in servaddr;
char banner[] = "Hello TCP server! This is TCP client";
char buffer[1000];
if (argc != 2)
{
printf("usage: ./%s <IP address>\n",argv[0]);
return -1;
}
/* socket to connect */s
sockfd=socket(AF_INET,SOCK_STREAM,0);
/* IP address information of the server to connect to */
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=inet_addr(argv[1]);
servaddr.sin_port=htons(32000);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
sendto(sockfd,banner,strlen(banner),0, (struct sockaddr*)&servaddr,sizeof(servaddr));
n=recvfrom(sockfd,buffer,10000,0,NULL,NULL);
buffer[n]=0;
printf("Received:%s\n",buffer);
return 0;
}
Your main problem is that you are not checking the results of any of your operations on the sockets, so it is entirely possible that the server or client is reporting an error message that makes the answer to your problem obvious.
In particular, if the server fails to bind or listen to the listen socket, it will just go into an infinite loop making failed accepts, reads and writes forever.
I suspect that, what happens is that when you restart the server, the previous socket is still in the TIME_WAIT state, so it can't bind to the port. You can get around this by using the following after creating the socket:
int reuseaddr = 1;
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&reuseaddr,sizeof(reuseaddr))==-1)
{
fprintf(stderr, "%s",strerror(errno));
exit(1);
}
Note how the above checks the return result and reports an error on failure. You need to do this or similar after every call to socket(), listen(), bind(), connect(), recvfrom(), sendto() and close().
Note, how I put close() in that list. You really must call it on the connect socket when you are finished with it, especially on the server or you will leak the file descriptor in connfd.
I know that this is obviously elementary question and I know that there are many tutorials and ready-to-go examples but I must missing something. I am trying to send for example text (char *) via UDP socket to other machine in local network. So far I tried some tutorials like http://gafferongames.com/networking-for-game-programmers/sending-and-receiving-packets/ and so on but I always get error in bind() function with errno "Cannot assign requested address".
I just have some data in char array and I want to push them via network to another host. Could someone please point me to the right direction? Do I need socket server or client? Do I need to bind the socket to some interface?
This is my playground:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
int handle;
int init_socket()
{
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (handle <= 0)
{
printf("failed to create socket\n");
return 1;
}
printf("sockets successfully initialized\n");
return 0;
}
int main ()
{
unsigned short port = 30000;
char * data = "hovno";
init_socket();
struct sockaddr_in address;
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.11.129"); // this is address of host which I want to send the socket
address.sin_port = htons(port);
printf("handle: %d\n", handle); // prints number greater than 0 so I assume handle is initialized properly
if (bind(handle, (const struct sockaddr*) &address, sizeof(struct sockaddr_in)) < 0)
{
printf("failed to bind socket (%s)\n", strerror(errno)); // Cannot assign requested address
return 1;
}
int nonBlocking = 1;
if (fcntl(handle, F_SETFL, O_NONBLOCK, nonBlocking) == -1)
{
printf("failed to set non-blocking\n");
return 2;
}
int sent_bytes = sendto(handle, data, strlen(data), 0, (const struct sockaddr*) &address, sizeof(struct sockaddr_in));
if (sent_bytes != strlen(data))
{
printf("failed to send packet\n");
return 3;
}
return 0;
}
bind is called for the local address (one you intend to recv packets to). The IP address must be a local IP address of the machine, or (most frequently) INADDR_ANY.
Normally you don't have to use bind on the client side at all. The system will pick a suitable free port for you automatically.
To specify the remote address for a UDP socket, use sendto, not send.
If you search Google for udp client c code, one of the first results is this one. You can see that the networking part is basically just two calls, socket and sendto.