Related
I am a C beginner. I want to send a file by TCP. The client reads content from a txt file and sent it to server. Read method is ok. It reads the specified bytes from the file. Send method dose not throw any exception. However the server receives nothing. I try to solve it for a whole day. I fail.
Please help me check what is wrong with my code.
As comment advice, I edit my code again. Now there are two problem. One is that in the client loop the return values from client fread() and send() is greater than 0 for the first two times while the server accept() is still blcoked without getting message from client.
The second problem. In the third client loop, the return value of client fread() is still greater than 0, but the return value of send() is -1.I try to open the file in binary mode rb instead of r. It is the same problem.
the edited client code:
#include <stdio.h>
#include <winsock.h>
#include <time.h>
#pragma comment(lib, "WS2_32.lib")
#define MAXLINE 1024*4
SOCKET sockClient;// = socket(AF_INET,SOCK_DGRAM,0);
SOCKADDR_IN servAddr;
int main(void) {
WSADATA wsd;
FILE *fp;
int read_len;
char buf2[MAXLINE];
time_t t_start, t_end;
if ((fp = fopen("file.txt", "r")) == NULL) {
perror("Open file failed\n");
exit(0);
}
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
printf("WSAStartup failed !\n");
return 1;
}
sockClient = socket(AF_INET, SOCK_STREAM, 0);
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons(5000);
/* connect the server commanted by guoqingbo*/
int i_ret = connect(sockClient, (struct sockaddr *) &servAddr, sizeof(struct sockaddr));
if (-1 == i_ret) {
perror("Connect socket failed!\n");
exit(0);
}
printf("client starts\n");
t_start = time(NULL);
while (1) {
read_len = fread(buf2, sizeof(char), MAXLINE, fp);
if (read_len < 0) {
perror("read data failed\n");
break;
} else if (read_len == 0) {
printf("read finished\n");
}
int send_len = send(sockClient, buf2, read_len, 0);
if (send_len < 0) {
perror("Send data failed\n");
exit(0);
} else if (send_len == 0) {
printf("send finished\n");
break;
}
}
t_end = time(NULL);
printf("The time used %f s\n", difftime(t_end, t_start));
fclose(fp);
closesocket(sockClient);
WSACleanup();
return 0;
}
the edited server code:
#include <stdio.h>
#include <WINSOCK2.H>
#include <strings.h>
#include <stdlib.h>
#pragma comment(lib, "WS2_32.lib")
#define BUF_SIZE 1024*4
SOCKET socketSrv;
SOCKADDR_IN addrSrv;
SOCKADDR_IN addrClient;
char buf[BUF_SIZE];
int main(void) {
WSADATA wsd;
int nRet;
int recv_len;
FILE *fp;
if ((fp = fopen("file.txt", "w")) == NULL) {
perror("Creat file failed");
exit(0);
}
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
printf("WSAStartup failed !\n");
return 1;
}
socketSrv = socket(AF_INET, SOCK_STREAM, 0);
int len = sizeof(SOCKADDR);
ZeroMemory(buf, BUF_SIZE);
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(5000);
nRet = bind(socketSrv, (SOCKADDR *) &addrSrv, sizeof(SOCKADDR));
if (SOCKET_ERROR == nRet) {
printf("bind failed !\n");
closesocket(socketSrv);
WSACleanup();
return -1;
}
if (SOCKET_ERROR == listen(socketSrv, 10)) {
printf("Server Listen Failed: %d", WSAGetLastError());
exit(1);
}
printf("server started..\n");
while (1) {
SOCKET m_New_Socket = accept(socketSrv, (SOCKADDR *) &addrClient, &len);
if (SOCKET_ERROR == m_New_Socket) {
printf("Server Accept Failed: %d", WSAGetLastError());
break;
}
if (recv_len = recv(socketSrv, buf, BUF_SIZE, 0) < 0) {
printf("Server Receive Data Failed!");
break;
}
int write_length = fwrite(buf, sizeof(char), recv_len, fp);
if (write_length < recv_len) {
printf("File write failed\n");
break;
}
}
fclose(fp);
closesocket(socketSrv);
WSACleanup();
return 0;
}
I want the server to send a OTP (one-time password) to the client. Then the client sends the password back to the server it was received from, and if they match then furthur conversation happens.
This code is for server side:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
// Create a listen socket
int listen_socket = socket(PF_INET, SOCK_STREAM, 0);
// Create Local Server address and initialise family, port number, IP address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(10000);
server_address.sin_addr.s_addr = INADDR_ANY;
// bind listen socket with local server address
bind(listen_socket, (struct sockaddr*)&server_address, sizeof(struct sockaddr_in));
// listen for a connection
listen(listen_socket, 10);
// accept a connection to create socket for data exchange
int data_exchange_socket = accept(listen_socket, NULL, NULL);
//--------------------------------- LOGIC ----------------------------------------
//OTP for authentication
char* server_password = "vikas#hplap";
// send OTP to client
send(data_exchange_socket, server_password, strlen(server_password), 0);
// recieve OTP
char* client_password;
recv(data_exchange_socket, client_password, 50, 0);
// authenticate
if(strcmp(server_password, client_password) == 0)
{
// Correct OTP sent by client
char* server_verdict = "Correct";
send(data_exchange_socket, server_verdict, strlen(server_verdict), 0);
// get client message
char* client_message;
recv(data_exchange_socket, client_message, 50, 0);
printf("Client Message: %s\n", client_message);
//server respond with hello
char* server_response = "Hello, Press any key to exit...";
send(data_exchange_socket, server_response, strlen(server_response), 0);
printf("Data sent\n"); // This doesn't execute
}
else
{
// handle wrong OTP by client
char* server_response = "Incorrect OTP entered!";
send(data_exchange_socket, server_response, strlen(server_response), 0);
}
// shut down server
printf("Server Closed :)\n"); // This is also not executed
close(listen_socket);
return 0;
}
Here is the code for the client side:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
// create socket for data exchange
int data_exchange_socket = socket(PF_INET, SOCK_STREAM, 0);
// create remote server address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(10000);
server_address.sin_addr.s_addr = INADDR_ANY;
// try to connect with server
int status=connect(data_exchange_socket, (struct sockaddr *)&server_address, sizeof(struct sockaddr_in));
if(status==-1)
{
printf("\n connection error.....");
}
// recieve OTP from server
char* otp;
recv(data_exchange_socket, otp, 50, 0);
// send server the otp recieved
send(data_exchange_socket, otp, strlen(otp), 0);
// recieve server message
char* server_verdict;
recv(data_exchange_socket, server_verdict, 50, 0);
if(strcmp(server_verdict, "Correct") == 0)
{
// Send "Hi" to server
char* client_response = "Hi";
send(data_exchange_socket, client_response, strlen(client_response), 0);
// recieve server message
char* server_message;
recv(data_exchange_socket, server_message, 50, 0);
printf("Server Message: %s\n", server_message);
}
close(data_exchange_socket);
return 0;
}
I think it is because maybe we can only receive once with one data_exchange_socket. But then I didn't find it true for the client code.
Please tell me if the above is true. I cannot understand why it doesn't work.
You are not handling your string transmissions correctly. You are not framing your strings in such a way, either by sending the string length or the null terminator, so that the receiver can know when to stop reading each string. And you are not allocating any memory for recv() to read into. Or accounting for the fact that TCP is a stream so there is no 1:1 relationship between send() and recv(), partial sends/reads are possible.
Try something more like this instead:
Common:
int sendString(int sock, const char *str)
{
size_t len = strlen(str) + 1;
int numSent;
while (len > 0)
{
numSent = send(sock, str, len, 0);
if (numSent < 0)
return -1;
str += numSent;
len -= numSent;
}
return 0;
}
int recvString(int sock, char **msg)
{
size_t len = 0, cap = 0, size;
char ch, *newmsg;
int numRecv;
*msg = NULL;
do
{
numRecv = recv(sock, &ch, 1, 0);
if (numRecv <= 0)
{
free(*msg);
*msg = NULL;
return numRecv;
}
if (len == cap)
{
size = (ch == '\0') ? (len + 1) : (len + 50);
newmsg = realloc(*msg, size);
if (newmsg == NULL)
{
free(*msg);
*msg = NULL;
return -1;
}
memcpy(newmsg, *msg, len);
*msg = newmsg;
cap = size;
}
(*msg)[len] = ch;
++len;
}
while (ch != '\0');
return 1;
}
Alternatively:
int sendRaw(int sock, void *data, size_t size)
{
char *pdata = data;
int numSent;
while (size > 0)
{
numSent = send(sock, pdata, size, 0);
if (numSent < 0)
return -1;
pdata += numSent;
size -= numSent;
}
return 0;
}
int recvRaw(int sock, void *data, size_t size)
{
char *pdata = data;
int numRecv;
while (size > 0)
{
numRecv = recv(sock, pdata, size, 0);
if (numRecv <= 0)
return numRecv;
pdata += numRecv;
size -= numRecv;
}
return 1;
}
int sendUInt32(int sock, uint32_t val)
{
val = htonl(val);
return sendRaw(sock, &val, sizeof(val));
}
int recvUInt32(int sock, uint32_t *val)
{
int res = recvRaw(sock, val, sizeof(*val));
if (res <= 0) return res;
*val = ntohl(*val);
return 1;
}
int sendString(int sock, const char *str)
{
size_t len = strlen(str);
if (sendUInt32(sock, len) < 0) return -1;
return sendRaw(sock, str, len);
}
int recvString(int sock, char **msg)
{
*msg = NULL;
uint32_t len;
int res = recvUInt32(sock, &len);
if (res <= 0)
return res;
char *newmsg = malloc(len + 1);
if (newmsg == NULL)
return -1;
res = recvRaw(sock, newmsg, len);
if (res <= 0)
{
free(newmsg);
return res;
}
newmsg[len] = '\0';
*msg = newmsg;
return 1;
}
Then you can do this:
Server:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include "Common.h"
int main(int argc, char* argv[])
{
// Create a listen socket
int listen_socket = socket(PF_INET, SOCK_STREAM, 0);
if (listen_socket < 0)
{
perror("Error creating listening socket");
return -1;
}
// Create Local Server address and initialize family, port number, IP address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(10000);
server_address.sin_addr.s_addr = INADDR_ANY;
// bind listen socket with local server address
if (bind(listen_socket, (struct sockaddr*)&server_address, sizeof(struct sockaddr_in)) < 0)
{
perror("Error binding listening socket");
close(listen_socket);
return -1;
}
// listen for a connection
if (listen(listen_socket, 10) < 0)
{
perror("Error opening listening socket");
close(listen_socket);
return -1;
}
// accept a connection to create socket for data exchange
int data_exchange_socket = accept(listen_socket, NULL, NULL);
if (data_exchange_socket < 0)
{
perror("Error accepting a client");
close(listen_socket);
return -1;
}
//--------------------------------- LOGIC ----------------------------------------
//OTP for authentication
// send OTP to client
if (sendString(data_exchange_socket, "vikas#hplap") < 0)
{
perror("Error sending password to client");
close(data_exchange_socket);
close(listen_socket);
return 0;
}
// receive OTP
char* client_password;
int res = recvString(data_exchange_socket, &client_password);
if (res <= 0)
{
if (res < 0)
perror("Error receiving password from client");
else
printf("Disconnected while receiving password from client\n");
close(data_exchange_socket);
close(listen_socket);
return 0;
}
// authenticate
int res = strcmp(server_password, client_password);
free(client_password);
if (res == 0)
{
// Correct OTP sent by client
if (sendString(data_exchange_socket, "Correct") < 0)
{
perror("Error sending verdict to client");
close(data_exchange_socket);
close(listen_socket);
return 0;
}
// get client message
char* client_message;
res = recvString(data_exchange_socket, &client_message);
if (res <= 0)
{
if (res < 0)
perror("Error receiving message from client");
else
printf("Disconnected while receiving message from client\n");
close(data_exchange_socket);
close(listen_socket);
return 0;
}
printf("Client Message: %s\n", client_message);
free(client_message);
//server respond with hello
if (sendString(data_exchange_socket, "Hello, Press any key to exit...") < 0)
{
perror("Error sending message to client");
close(data_exchange_socket);
close(listen_socket);
return 0;
}
printf("Data sent\n"); // This doesn't execute
}
else
{
// handle wrong OTP by client
if (sendString(data_exchange_socket, "Incorrect OTP entered!") < 0)
{
perror("Error sending verdict to client");
close(data_exchange_socket);
close(listen_socket);
return 0;
}
}
// shut down server
printf("Server Closed :)\n"); // This is also not executed
close(data_exchange_socket);
close(listen_socket);
return 0;
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include "Common.h"
int main(int argc, char* argv[])
{
// create socket for data exchange
int data_exchange_socket = socket(PF_INET, SOCK_STREAM, 0);
if (data_exchange_socket < 0)
{
perror("Error creating socket");
return -1;
}
// create remote server address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(10000);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
// try to connect with server
if (connect(data_exchange_socket, (struct sockaddr *)&server_address, sizeof(struct sockaddr_in)) < 0)
{
perror("Error connecting to server");
close(data_exchange_socket);
return -1;
}
// recieve OTP from server
char* otp;
int res = recvString(data_exchange_socket, &otp);
if (res <= 0)
{
if (res < 0)
perror("Error receiving password from server");
else
printf("Disconnected while receiving password from server\n");
close(data_exchange_socket);
return -1;
}
// send server the otp received
if (sendString(data_exchange_socket, otp) < 0)
{
perror("Error sending password to server");
free(otp);
close(data_exchange_socket);
return -1;
}
free(otp);
// receive server message
char* server_verdict;
res = recvString(data_exchange_socket, &server_verdict);
if (res <= 0)
{
if (res < 0)
perror("Error receiving verdict from server");
else
printf("Disconnected while receiving verdict from server\n");
close(data_exchange_socket);
return -1;
}
res = strcmp(server_verdict, "Correct");
free(server_verdict);
if (res == 0)
{
// Send "Hi" to server
if (sendString(data_exchange_socket, "Hi") < 0)
{
perror("Error sending message to server");
close(data_exchange_socket);
return -1;
}
// recieve server message
char* server_message;
res = recvString(data_exchange_socket, &server_message);
if (res <= 0)
{
if (res < 0)
perror("Error receiving message from server");
else
printf("Disconnected while receiving message from server\n");
close(data_exchange_socket);
return -1;
}
printf("Server Message: %s\n", server_message);
free(server_message);
}
close(data_exchange_socket);
return 0;
}
This is my client program that requests files from the server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 5959
#define MAX_LINE 512
void setstring(char *str){
str[MAX_LINE-1]='\0';
}
int main(int argc, char * argv[]){
FILE *fp;
struct hostent *hp;
struct sockaddr_in sin;
char *host;
char filename[MAX_LINE],buf[MAX_LINE],reply[MAX_LINE],rec_line[MAX_LINE];
int s;
char msg[MAX_LINE];
int len,new_len,rec_file;
if (argc==2) {
host = argv[1];
}
else {
fprintf(stderr, "usage: simplex-talk host\n");
exit(1);
}
/* translate host name into peer's IP address */
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "simplex-talk: unknown host: %s\n", host);
exit(1);
}
else
printf("Client's remote host: %s\n", argv[1]);
/* build address data structure */
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
sin.sin_port = htons(SERVER_PORT);
/* active open */
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("simplex-talk: socket");
exit(1);
}
else
printf("Client created socket.\n");
int send_file_name,rec_msg;
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("simplex-talk: connect");
close(s);
exit(1);
}
else{
printf("Client connected.\n");
/* main loop: get and send lines of text */
printf("Hello from server\n");
while(!(strcmp(reply,"bye")==0)){
printf("Enter the file name:\n");
scanf("%s",filename);
setstring(filename);
send_file_name=send(s,filename,strlen(filename)+1,0);
if(send_file_name<0)
fputs("Error sending filename",stdout);
rec_msg=recv(s,msg,sizeof(msg),0);
if(strcmp(msg,"File not found")==0)
printf("File not found\n");
else{
printf("%s\n",msg);
fp=fopen(filename,"w");
printf("CP1\n");
if(rec_file=recv(s,rec_line,sizeof(rec_line),0)>0){
printf("CP2");
printf("String recieved:%s\n",rec_line);
if(len=fwrite(rec_line,1,rec_file+1,fp)>0)
printf("Recieved file\n");
else
printf("Error writing to file\n");
}
else
printf("Not recieved\n");
}
printf("Enter 'bye' to terminate requesting files\n");
scanf("%s",reply);
}
}
return 0;
}
This is my server program that accepts request for files from the client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 5959
#define MAX_PENDING 5
#define MAX_LINE 256
void setstring(char* str){
str[MAX_LINE-1]='\0';
}
int main(){
FILE *fp;
struct sockaddr_in sin;
char buf[MAX_LINE],msg[MAX_LINE],*rec_line;
int len;
int s, new_s,count;
char str[INET_ADDRSTRLEN];
int error_file,send_msg,read_line,send_file;
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("0.0.0.0");
sin.sin_port = htons(SERVER_PORT);
/* setup passive open */
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("simplex-talk: socket");
exit(1);
}
inet_ntop(AF_INET, &(sin.sin_addr), str, INET_ADDRSTRLEN);
printf("Server is using address %s and port %d.\n", str, SERVER_PORT);
if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0) {
perror("simplex-talk: bind");
exit(1);
}
else
printf("Server bind done.\n");
listen(s, MAX_PENDING);
/* wait for connection, then receive and print text */
while(1) {
if ((new_s = accept(s, (struct sockaddr *)&sin, &len)) < 0) {
perror("simplex-talk: accept");
exit(1);
}
printf("Server Listening.\n");
printf("Greetings\n");
int rec_file_name=recv(new_s,buf,sizeof(buf),0);
if(rec_file_name>0)
printf("File requested:%s\n",buf);
fp=fopen(buf,"r");
if(fp==NULL)
{
fputs("File not found\n",stdout);
strcpy(buf,"File not found");
if(error_file=send(new_s,buf,strlen(buf)+1,0)>0)
fputs("Successfully send error message to client\n",stdout);
}
else{
bzero(buf,MAX_LINE);
printf("File found :) \n");
strcpy(buf,"OK");
if(send_msg=send(new_s,buf,strlen(buf)+1,0)>0)
fputs("File found message sent to client\n",stdout);
fseek(fp,0,SEEK_END);
int file_size=ftell(fp);
fseek(fp,0,SEEK_SET);
printf("File size:%d\n",file_size);
rec_line=(char *)malloc(sizeof(char)*(file_size));
read_line=fread(rec_line,1,file_size+1,fp);
printf("File read: %s\n",rec_line);
if(send_file=send(new_s,rec_line,strlen(rec_line)+1,0)>0)
printf("File string sent to client\n");
}
}
close(new_s);
}
The problem is that in the client, my second recv() call, where it is supposed to receive the contents of a file, shows nothing. The programs halts at that point, but the server programs displays that it has sent the file contents. The client doesn't receive it.
The basic problem is that you're not checking the return values to see how much data you actually sent and received. So when the client calls:
rec_msg=recv(s,msg,sizeof(msg),0);
it will receive up to sizeof(msg) (512) bytes, which is probably both the OK message the server is sending AND the file contents (after the NUL). Which means when it does a second recv call to get the contents, it blocks, because it already read the contents in the first call and there's no more data waiting in the receive buffer.
Your error-checking is haphazard, and consequently you're certainly missing a problem that occurs before the behavior you're observing. I recommend you follow RW Steven's idiom:
int n;
if( (n = recv(new_s, buf, sizeof(buf), 0)) < 0 ) {
err(EXIT_FAILURE, "recv %d", __LINE__);
}
Test every function call, and handle every error. For simple programs, just call err(3) on error. Do that consistently, and the program's behavior will be much less mysterious (if still occasionally surprising). And don't be afraid of the spacebar! It's easy to hit, and easier still to read.
My other bit of advice, if I may, concerns
int send_file_name,rec_msg;
Names like that are confusing. A name is almost never an integer. For I/O sizes, just use one simple name like n, len, or size. Even if you don't care for yourself, you want to care before publishing your question in an open forum. Otherwise, when people see
send_file_name=send(s,filename,strlen(filename)+1,0);
they may think send is some function other than send(2), or that the person asking the question was careless.
The main problem I see is that neither the client nor the server are handling socket I/O correctly in general. They are not handling the cases where reads and writes transfer fewer bytes then requested, you need to loop the I/O. And the client is reading too many bytes from the server anyway, which is why your second recv() is blocking. And you are relying on a disconnect to indicate the end of the file has been reached, but that does not allow the client to do adequate error checking to know if the full file was actually received or not.
Also, when sending the content of a file, the server is attempting to read the entire file into memory (bad!), not doing adequate error checking on the file I/O, and it is treating the file content as text instead of as binary (don't use strlen() on binary data!).
Try something more like this instead:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 5959
#define MAX_LINE 512
int sendstring(int sock, const char *str) {
if (!str) str = "";
int len = strlen(str) + 1;
do {
int ret = send(sock, str, len, 0);
if (ret <= 0) return -1;
str += ret;
len -= ret;
}
while (len > 0);
return 0;
}
int readbuf(int sock, void *buf, int buflen) {
char *pbuf = (char*) buf;
while (buflen > 0) {
int len = recv(sock, pbuf, buflen, 0);
if (len <= 0) return -1;
pbuf += len;
buflen -= len;
}
return 0;
}
int readstring(int sock, char *str, int maxlen) {
while (maxlen > 0) {
if (recv(sock, str, 1, 0) <= 0) return -1;
if (*str == '\0') return 0;
++str;
--maxlen;
}
return -2;
}
int readfile(int sock, int fd) {
int filesize;
char buf[MAX_LINE];
if (readbuf(sock, &filesize, sizeof(filesize)) < 0) return -1;
filesize = ntohl(filesize);
while (filesize > 0) {
int len = readbuf(sock, buf, min(sizeof(buf), filesize));
if (len < 0) return -1;
if (fwrite(buf, len, 1, fp) != 1) return -2;
filesize -= len;
}
return 0;
}
int main(int argc, char * argv[]) {
char filename[MAX_LINE], reply[MAX_LINE];
if (argc != 2) {
fprintf(stderr, "usage: simplex-talk host\n");
exit(1);
}
char *host = argv[1];
/* translate host name into peer's IP address */
struct hostent *hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "simplex-talk: unknown host: %s\n", host);
exit(1);
}
if (hp->h_addrtype != AF_INET) {
fprintf(stderr, "simplex-talk: unsupported address type %d for host: %s\n", hp->h_addrtype, host);
exit(1);
}
/* build address data structure */
struct sockaddr_in sin;
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
sin.sin_port = htons(SERVER_PORT);
printf("Host's remote IP: %s\n", inet_ntoa(&sin.sin_addr));
/* active open */
int s = socket(PF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("simplex-talk: socket");
exit(1);
}
printf("Client created socket.\n");
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("simplex-talk: connect");
close(s);
exit(1);
}
printf("Client connected.\n");
/* main loop: get and send lines of text */
do {
printf("Enter the file name ('bye' to quit):\n");
if (scanf("%512s", filename) != 1) {
printf("Error reading filename\n");
break;
}
if (strcmp(filename, "bye") == 0) {
sendstring(s, "bye");
break;
}
if (sendstring(s, filename) < 0) {
printf("Error sending filename\n");
break;
}
if (readstring(s, reply, sizeof(reply)) < 0) {
printf("Error reading reply\n");
break;
}
if (strcmp(reply, "OK") != 0) {
printf("%s\n", reply);
if (strcmp(reply, "bye") == 0) break;
continue;
}
FILE *fp = fopen(filename, "wb");
if (!fp) {
printf("Error opening file\n");
break;
}
printf("Receiving file\n");
int ret = readfile(s, fd);
fclose(fp);
if (ret < 0) {
if (ret == -2)
printf("Error writing file\n");
else
printf("Error reading file\n");
break;
}
printf("Received file\n");
}
while (1);
close(s);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 5959
#define MAX_PENDING 5
#define MAX_LINE 512
int sendbuf(int sock, void *buf, int buflen) {
char *pbuf = (char*) buf;
while (len > 0) {
int len = send(sock, pbuf, buflen, 0);
if (len <= 0) return -1;
pbuf += len;
buflen -= len;
}
return 0;
}
int sendstring(int sock, const char *str) {
if (!str) str = "";
return sendbuf(sock, str, strlen(str) + 1);
}
int sendfile(int sock, int fd) {
char buf[MAX_LINE];
struct stat s;
if (fstat(fd, &s) < 0) return -2;
int pos = ftell(fp);
if (pos == -1) return -2;
int file_size = s.st_size - pos;
int tmp_file_size = htonl(file_size);
if (sendbuf(sock, &tmp_file_size, sizeof(tmp_file_size)) < 0) return -1;
while (file_size > 0) {
int len = fread(buf, 1, min(sizeof(buf), file_size), fp);
if (len < 1) return -2;
if (sendbuf(sock, buf, len) < 0) return -1;
file_size -= len;
}
return 0;
}
int readstring(int sock, char *str, int maxlen) {
while (maxlen > 0) {
if (recv(sock, str, 1, 0) <= 0) return -1;
if (*str == '\0') return 0;
++str;
--maxlen;
}
return -2;
}
int main() {
char msg[MAX_LINE];
struct sockaddr_in sin;
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVER_PORT);
/* setup passive open */
int s = socket(PF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("simplex-talk: socket");
exit(1);
}
printf("Server is using address %s and port %d.\n", inet_ntoa(&(sin.sin_addr)), SERVER_PORT);
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("simplex-talk: bind");
close(s);
exit(1);
}
printf("Server bind done.\n");
if (listen(s, MAX_PENDING) < 0) {
perror("simplex-talk: listen");
close(s);
exit(1);
}
printf("Server Listening.\n");
/* wait for connection, then receive and print text */
do {
int len = sizeof(sin);
int cli_s = accept(s, (struct sockaddr *)&sin, &len);
if (cli_s < 0) {
perror("simplex-talk: accept");
close(s);
exit(1);
}
printf("Client connected\n");
do {
if (readstring(cli_s, msg, sizeof(msg)) < 0) {
printf("Error reading request\n");
break;
}
if (strcmp(msg, "bye") == 0) break;
printf("File requested: %s\n", msg);
FILE *fp = fopen(msg, "rb");
if (!fp)
{
printf("Cannot open file\n");
if (sendstring(cli_s, "Cannot open file") < 0) {
printf("Error sending reply\n");
break;
}
continue;
}
printf("File found :) \n");
if (sendstring(cli_s, "OK") < 0) {
printf("Error sending reply\n");
fclose(fp);
break;
}
ret = sendfile(cli_s, fp);
fclose(fp);
if (ret < 0) {
printf("Error sending file\n");
break;
}
printf("File sent to client\n");
}
while (1);
close(cli_s);
}
while (1);
close(s);
return 0;
}
I am trying to implement a simple HTTP server with C that
reads a request
checks if it is a GET request
reads the URL from the request
Checks if file is on server and tries to open it
I am using strtok for String tokenizing and I think it messes up the filepath. open and fopen always return error codes and are not able to open any files.
Here is my code:
/*
** parser.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MYPORT 3499 // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXLEN 1024 //upper limit of the length of the string
int main(void)
{
char input[MAXLEN]; //the line that is read from the client
char * token1; //GET request
char * token2; //filepath
char tmpstring[MAXLEN]; //filesize
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd, file open on file_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
int sin_size;
int yes=1;
int n; //the amount of read characters from the client
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
while(1) { // main accept() loop
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
n = readline(new_fd, input, MAXLEN); //n is the amount of read characters
if (n == -1) {
perror("Unable to read line");
}
//Check if it is a GET message
token1 = strtok(input," ");
if(strcmp(token1, "GET") != 0)
{
send(new_fd, "Bad request\n", 30, 0);
}
else
{
//Retrieve the file path
token2 = strtok(NULL, " ");
if(token2 == NULL)
{
send(new_fd, "File path not specified\n", 23, 0); //Check if filename is empty
}
send(new_fd, token2, strlen(token2), 0); //test
printf("%s", token2);
if(token2[0] == '/') //remove the initial slash
memmove(token2, token2 + 1, strlen(token2));
//char * path = "test.html"; //test line
//char * buff;
//int len = sprintf(buff, "1: %d 2: %d\n", strlen(token1), strlen(token2));
//send(new_fd, buff, len, 0);
//Check if file is on the server
if(open(token2, O_RDONLY) < 0) //Error opening file
{
if(errno == EACCES)
send(new_fd, "Access error\n", 30, 0);
else
send(new_fd, "Not existed\n", 30, 0);
}
else
{
FILE * requested_file = fopen(token2, "r");
if(requested_file == NULL) //
{
send(new_fd, "Error in fopen\n", 30, 0);
}
else
{
send(new_fd, "File found\n", 30, 0); //successful
}
fseek(requested_file, 0, SEEK_END); // move to the end of the file
int end= ftell(requested_file); // get the position of the end of file
int stringlen = sprintf(tmpstring, "file size: %d\n", end);
send(new_fd, tmpstring, stringlen, 0);
}
}
close(new_fd); //close connection
}
return 0;
}
//helper function for recieving text
int readline(int fd, char *buf, int maxlen)
{
int n, rc;
char c;
for (n = 1; n < maxlen; n++) {
if ((rc = read(fd, &c, 1)) == 1) {
*buf++ = c;
if (c == '\n')
break;
} else if (rc == 0) {
if (n == 1)
return 0; // EOF, no data read
else
break; // EOF, read some data
} else
return -1; // error
}
*buf = '\0'; // null-terminate
return n;
}
So I'm placing a test.html in the same folder as the server. Then im telnetting to localhost and port 3499. This is the output when entering GET /test.html:
/test.html
Not existed
rError in fopen
Connection closed by foreign host.
try opening "test.html" instead of "\test.html"
I have this code, simple socket C example code, it works fine for an simple servidor that I wrote and run on local computer,but if I try for example, get html from google web page, it delay significantly the time of reply and returns empty buffer.
my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
void bye(char * mmo);
void bye(char * mm) {
printf("%s\n", mm);
exit(0);
}
int main(void) {
int tcpSocket, port;
char buffer[256],err[256], *servername,* mm;
struct hostent *server;
struct sockaddr_in serverAddr;
servername = "google.com";
tcpSocket = socket(AF_INET, SOCK_STREAM, 0);
port = 80;
server = gethostbyname(servername);
mm = "baa";
if(tcpSocket < 0) {
sprintf(err, "Can't to initialize TCP socket communication(%s).", strerror(errno));
bye(err);
}
if(NULL == server) {
bye("Server not found");
}
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
memcpy(&serverAddr.sin_addr.s_addr,
server->h_addr,
server->h_length);
serverAddr.sin_port = htons(port);
if(connect(tcpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
sprintf(err, "failed internet connection. %s", strerror(errno));
bye(err);
}
if(write(tcpSocket, mm, strlen(mm)) < 0) {
sprintf(err, "Can't send.(%s)\n", strerror(errno));
bye(err);
}
memset(buffer, 0, sizeof(buffer));
while(read(tcpSocket, buffer, 255) < 0) {
printf("%s", buffer);
}
close(tcpSocket);
printf("done!\n");
return 0;
}
Thanks in advance.:)
Referring the code that reads the result:
while(read(tcpSocket, buffer, 255) < 0) {
printf("%s", buffer);
}
Such code only prints out the buffer´s content in case read() returned a vlaue less then 0, which read does in case of an error.
You might like to modify your code like so:
{
size_t sizeReadTotal = 0;
size_t sizeToRead = 255;
ssize_t ssizeRead = 0;
while (sizeToRead && (ssizeRead = read(tcpSocket, buffer + sizeReadTotal, sizeToRead))) {
if (0 > sizeRead) {
if (EAGAIN == errno || EWOULDBLOCK == errno)
continue;
else
break;
}
sizeToRead -= ssizeRead;
sizeReadTotal += ssizeRead;
}
if (0 > ssizeRead)
printf("read() failed after having read %dbytes: %s\n", sizeReadTotal, strerror(errno));
printf("Data read: '%s'\n", buffer);
}
Further more you should also send the '\n' to the server also (as selbie mentioned), so change:
mm = "baa";
into
mm = "baa\n";