I'm creating a TCP chat room in C with fork()
. Every client message should reach server with username and message in buffer, so I use strcpy(buffer, name)
and strcat(buffer, ": ")
to combine buffer and name. After that I use
n = write (sockfd, buffer, strlen(buffer))
to send buffer to server. So right here strange thing happens, my server show nothing, but after that when I use
n = read(sockfd, buffer, 255);
printf("%s", buffer);
string is correctly transferred. Here is my server code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>
int main(){
int port;
int i = 1;
printf("Enter port ->");
scanf("%d", &port);
int sockfd, newsockfd, n;
char buffer[255];
struct sockaddr_in6 serv_addr, cli_addr;
int ret, flag;
sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0){
printf("Error opening socket\n");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
flag = 1;
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if (ret < 0){
printf("Set sock opt errror\n");
}
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_addr = in6addr_any;
serv_addr.sin6_port = htons(port);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
printf("Error binding\n");
}
listen(sockfd, 5);
int clilen = sizeof(cli_addr);
int pid;
while(1){
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0){
printf("Error on accept\n");
}
printf("New connection\n");
pid = fork();
if (pid < 0){
printf("Error on pid\n");
}
if (pid == 0){
close(sockfd);
while(1){
bzero(buffer, 255);
n = read(newsockfd, buffer, 255);
if (n < 0){
printf("Error on reading\n");
}
printf("%s", buffer);
n = write(newsockfd, buffer, strlen(buffer));
if (n < 0){
printf("Error on writing\n");
}
}
}
}
close(newsockfd);
return 0;
}
and client code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(){
int port;
printf("Enter port ->");
scanf("%d", &port);
char ip[10];
printf("Enter ip -> ");
scanf("%s", &ip);
char name[20];
printf("Enter name -> ");
scanf("%s", &name);
int sockfd, n;
char buffer[255];
struct sockaddr_in6 serv_addr;
sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0){
printf("Error opening socket\n");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, "ip", &serv_addr.sin6_addr);
serv_addr.sin6_port = htons(port);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
printf("Connection failed\n");
}
while(1){
bzero(buffer, 255);
fgets(buffer, 255, stdin);
strcpy(buffer, name);
strcat(buffer, ": ");
n = write (sockfd, buffer, strlen(buffer));
bzero(buffer,255);
if (n < 0){
printf("Error on writing\n");
}
n = read(sockfd, buffer, 255);
printf("%s", buffer);
if (n < 0){
printf("Error on reading\n");
}
}
close(sockfd);
}
So maybe someone can see the problem why client can't send full buffer with name and message to server? I think the problem is something with name
. When I send only the buffer that I get using
fgets(buffer, 255, stdin);
server works fine, but I need client username.
I tried to test strlen(name)
and buffer
and everything seems okay. What I tried to do is manually convert name to buffer like this :
for (int i = 0; i < strlen(name); i++){
buffer[i] = name[i];
}
But then if it's the only way to do this, how should I push the buffer to the right entering name and don't lose message information?
Your code has plenty of errors :).
First of all scanf
takes as 1st argument a pointer, so when you want to use it for a string do:
char ip[10];
...
scanf("%s", ip);//THIS IS CORRECT
not scanf("%s", &ip);
.
On the server the compiler was complaining about the type of clilen
. accept
is expecting a sockelen_t
(or equivalently unsigned int
) while you declared that variable as a simple int
.
It is the following. In the client you did strcpy(buffer, name);
which copies name
starting from the beginning of the buffer but the beginning of the buffer actually contained your data. You should do something like the following using strcat
as you did in the next line:
bzero(buffer, 255);
fgets(buffer, 255, stdin);
strcat(buffer, name);
strcat(buffer, ": ");
Also note another thing: avoid mixing system call functions read
write
getchar
with library functions such as fread
, fwrite
, fgets
. I was having this problem with that causing by the fact that fgets
might read more bytes than expected. In your case should be ok because you are using them for different purposes.