Below is the code I inherited from my company (written by I don't know who) and this code is currently working for my specific scenario which is:
A piece of equipment (signal generator) sends me UDP data, and I need to receive the data, analyze it and sometimes send the equipment a command (based on the analysis). Here is what it looks like:
/*********************************************
** Communication Struct.
**********************************************/
typedef struct CtxCom
{
int socket_client; //socket
char* cmd; //command
char* recepbuff; //recepbuff
struct sockaddr_in addr_client; //contains IP and PORT
}CtxCom;
extern struct CtxCom init_Ctx_com ( char* IP_client, const int PORT_client, struct timeval timeout )
{
CtxCom ClientCom; //define struct
ClientCom.socket_client = socket(AF_INET, SOCK_DGRAM, 0); //Create the socket
if(ClientCom.socket_client < 0) //Check the creation of the socket
{
perror("[Init_Com] socket()");
exit(errno);
}
struct sockaddr_in addr_me = { 0 }; //create the server struct
addr_me.sin_addr.s_addr = htonl(INADDR_ANY); //any incoming IP
addr_me.sin_port = htons(PORT_client);
addr_me.sin_family = AF_INET; //address family
if(bind(ClientCom.socket_client,(struct sockaddr *) &addr_me, sizeof(addr_me)) < 0) //bind the socket
{
perror("[Init_Com] bind()");
exit(errno);
}
//conf equipment side
ClientCom.addr_client.sin_addr.s_addr = inet_addr(IP_client);
ClientCom.addr_client.sin_port = htons(PORT_client);
ClientCom.addr_client.sin_family = AF_INET;
//timeout
//setsockopt(ClientCom.socket_client , SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout , sizeof (struct timeval));
//fcntl(ClientCom.socket_client, F_SETFL, O_NONBLOCK); //set socket to non block
//Printf info
printf("[Init CtxCom]");
printf(" Socket connected and Client[%s:%d] configured *************** \n",
inet_ntoa(ClientCom.addr_client.sin_addr),
ntohs(ClientCom.addr_client.sin_port) );
return ClientCom;
}
/*Write char* cmd of size cmdSize in the socket specified*/
extern void write_client(struct CtxCom CtxCom, char* cmd, int cmdSize)
{
//adding 0x0a 0x0d to the end of a CMD
cmdSize+=2;
cmd[cmdSize-2]='\r';
cmd[cmdSize-1]='\n';
//send CMD
if(sendto(CtxCom.socket_client, cmd, cmdSize, 0, (struct sockaddr *)&(CtxCom.addr_client), sizeof(CtxCom.addr_client)) < 0)
{
perror("[Write_client] send()");
exit(errno);
}
else
{
//printf( "\n***************SEND OK [%s:%d]******************\n"
// ,inet_ntoa(CtxCom.addr_client.sin_addr), ntohs(CtxCom.addr_client.sin_port) );
}
}
* Give in output the char* strings outStringLLRX with a size of sizeOutStringLLRX*/
extern void read_client(
/*input*/ struct CtxCom CtxCom, struct timeval timeout,
/*output*/ char** outStringLLRX, int* sizeOutStringLLRX)
{
//timeout forced
//timeout.tv_usec=TIMEOUT_LISTEN_GIII;
//Define variables
fd_set readfs;
int loop=1;
int i=0, k=0, z=0, z_prev=0;
int res;
char buf[25500];
int sizeBuf;
//Init variables
memset(buf, '\0' ,sizeof(buf));
for(i=0;i<NB_CHANNELS_LLRX;i++)
{
sizeOutStringLLRX[i]=0;
outStringLLRX[i][0]='\0';
}
//Make sure buffer is empty
memset(buf, '\0' ,sizeof(buf)); //empty recep buffer
FD_ZERO(&readfs); //zero testing
FD_SET(CtxCom.socket_client, &readfs); // set testing
//block until input becomes available
res=select(CtxCom.socket_client+1, &readfs, NULL, NULL, &timeout);
switch (res)
{
case 0: //timeout
printf("TIMEOUT error [Read Client] - No data received \n");
break;
case -1: //error
printf("Error [Read Client] \n");
break;
default : //streams event
if( FD_ISSET(CtxCom.socket_client, &readfs) )
{
sizeBuf=recvfrom (CtxCom.socket_client, buf , 25500, 0, NULL, NULL); //already now which IP, no need to update
if ( sizeBuf<0 ) //if <0 => no data => error
{
printf("[Read_Client] Read failed : SizeBuf<0 \n");
}
else
{
printf("[Read_Client] Got a buffer of size %d (round %d) \n", sizeBuf, k);
(sizeOutStringLLRX[0])+=sizeBuf;
for( z=0; z<sizeBuf; z++) {outStringLLRX[0][z_prev]=buf[z]; z_prev++;}
}
}
break;
}//switch
//printf("[Read_Client] final size =%d\n", z_prev);
/*printf("***************RECV OK [%s:%d]******************\n",
inet_ntoa(CtxCom.addr_client.sin_addr),ntohs(CtxCom.addr_client.sin_port) );*/
}
I have read socket lesson and bind() man, but I'm still wondering: If I have another equipment that sends data on the same subnet, but in broadcast (on the x.255). Can this pollute the socket? and sometimes on the same socket when I'm receiving data from my equipment I received the broadcast instead (or in addition)?
In my case, bind is actually here just to "give a name" to the socket and not to accept any incoming IP address like it's written in the comment?
(Btw, if anything written here is really bad, let me know, I'll be glad to make this code better)
You shouldn't have to worry about receiving broadcast packets on the socket. Assuming Linux, man 7 ip tells us "Datagrams to broadcast addresses can be sent or received only when the SO_BROADCAST socket flag is set" (that flag can be set with setsockopt and is documented in man 7 socket).
bind() is used to select the port to listen to, but also which network interface. The interface is specified by its local address, and INADDR_ANY in this case means to listen on all network interfaces (see man 7 ip). The socket will receive data from any (valid) IP address on the selected interface(s).
Related
I have an application installed locally (not developed by me), which broadcasts UDP packets every second.
Reading the packets from my application (developed in C++ in Windows) which also is locally installed, works fine.
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOK = WSAStartup(version, &data);
SOCKET serverIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = INADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(UDP_RECEIVE_PORT);
bind(serverIn, (sockaddr*)&serverHint, sizeof(serverHint));
sockaddr_in client;
int clientSize = sizeof(client);
int RECIEVE_BUFFER_SIZE = 65507;
char* recieveBuffer = new char[RECIEVE_BUFFER_SIZE];
while(updating)
{
int bytesIn = recvfrom(serverIn, recieveBuffer, RECIEVE_BUFFER_SIZE, 0, (sockaddr*)&client, &clientSize);
}
closesocket(serverIn);
WSACleanup();
But I recently noticed while I was testing some code, while my app was running, that the bind(...)
function returned an error code of 10048 (WSAEADDRINUSE). Hence, it seems the first client bound to listen for the UDP packets is the only one who can listen, and the other clients is unable to read the broadcasted UDP packets.
So then I added the SO_REUSEADDR option before calling the bind(...) function to be able to bind successfully to the socket:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt((SOCKET)serverIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);
That works, but the recvfrom(...) function then does not recieve any data at all! I guess it waits for the other client to close its socket.
Next solution is to initialize the socket with SOCK_RAW instead.
The above option SO_REUSEADDR is now not needed, and remove it:
SOCKET serverIn = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
This works, I can read the data now! Though, Windows now requires the adminstrator rights for my application. Also I do recieve the UDP information in the data which I do not need.
Is there any better method to do this without requiring administrator rights, any possibility to discard the header information in the buffer?
Below is a little program I wrote to demonstrate that IPv4 UDP broadcast can and does work as expected under Windows (i.e. without requiring raw-sockets or Administrator privileges).
Run it with the command line argument "server" and it will send out one broadcast UDP packet per second.
Then also run several more instances of the same program, with no command line arguments, to receive the UDP packets and print a line of text to stdout whenever they do. The expected behavior should look like this:
As for why it's not working for you -- one possible guess is that your UDP-packet-sending program is actually sending out unicast UDP packets rather than broadcast. If that's the case, then I would expect that only one client program would receive packets (even if multiple clients are bound to the same port). A network trace tool like Wireshark might be able to help you determine if the UDP packets being sent are broadcast or unicast.
Anyway, here's the code:
#include <stdio.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32")
static int BindUDPSocket(SOCKET sock, unsigned short port, bool allowPortSharing)
{
if (sock == INVALID_SOCKET) return -1;
if (allowPortSharing)
{
const BOOL trueValue = true;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &trueValue, sizeof(trueValue)) < 0) return -1;
}
struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = INADDR_ANY; // aka 0.0.0.0
bindAddr.sin_port = htons(port);
return bind(sock, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
}
int main(int argc, char ** argv)
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
(void) WSAStartup(version, &data);
const unsigned short TEST_PORT = 12345;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock<0) {printf("socket() failed\n"); exit(10);}
if ((argc > 1)&&(strcmp(argv[1], "server") == 0))
{
if (BindUDPSocket(sock, 0, false)<0) {printf("BindUDPSocket() failed for server\n"); exit(10);}
const BOOL allowBroadcast = true;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &allowBroadcast, sizeof(allowBroadcast)) < 0)
{
printf("setsockopt(SO_BROADCAST) failed\n");
exit(10);
}
const char buf[] = {0x01, 0x02, 0x03, 0x04}; // dummy data
struct sockaddr_in toAddr; memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = INADDR_BROADCAST; // aka 255.255.255.255
toAddr.sin_port = htons(TEST_PORT);
printf("Sending outgoing broadcast UDP sockets on port %u, once per second\n", TEST_PORT);
while(true)
{
if (sendto(sock, buf, sizeof(buf), 0, (const sockaddr *) &toAddr, sizeof(toAddr)) == sizeof(buf))
{
printf("Sent %zu bytes of broadcast UDP data\n", sizeof(buf));
}
else printf("sendto() failed!\n");
Sleep(1000); // wait 1 second
}
}
else
{
if (BindUDPSocket(sock, TEST_PORT, true)<0) {printf("BindUDPSocket() failed for client\n"); exit(10);}
printf("Waiting to receive incoming broadcast UDP sockets on port %u\n", TEST_PORT);
while(true)
{
char buf[1024];
const int ret = recv(sock, buf, sizeof(buf), 0L);
printf("Received %i bytes of incoming UDP data\n", ret);
}
}
}
So, I am working on an remote ls assignment in which we have to use TCP socket connection between two remote computers and run client.c on one side and server.c on another. Client program enters command; for e.g: ls
the server will parse it and returns the current working directory to client.
Note that I am running both programs on VM Workstation. One side is Ubuntu and another is Red Hat 6.
Issue: My client program couldn't connect to the server and its connect() function is returning -1.
I have tried to debug my program and so I am attaching the results:debug result
Note: I have hardcoded IP address and port no for the sake of debugging.
Here are the codes:
Client side:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<netdb.h>
#include <string.h>
#include<unistd.h>
/*
Client side socket flow
socket()
|
|
v
connect()
|
|
v
recv()
*/
int main(int argc, char *argv[]) {
struct hostent *server;
struct sockaddr_in server_address;
int port_num;
int communication_status;
//create a socket
int network_socket;
//We will use 3 args while running client code.
/*
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
}*/
/*
socket(arg1,arg2,arg3)
- First arg: (AF_INET) = domain .. from IPV4 domain
- Sec arg: SOCK_STREAM - TCP Stream/Connection-Oriented
- Third arg: defines protocol - 0 for TCP <You can use RAW SOCKET HERE (SOCKETS WITH NO PROTOCOL)
*/
network_socket = socket(AF_INET,SOCK_STREAM,0);
/*
- So we can pass port no as int
- But data format is different from structure that we need to use a conversion function
- conversion function thats going to put our integer
port in right byte order is htons(agr = actual int port number we want to connect to)
*/
//define port you need to conenct remotely
port_num = 20102;
server_address.sin_port = htons(port_num);
//define server address
/*
-sin addr is field that contains structure itself
- we can use any address -- use shortcut ip.0.0.0 (INADDR_ANY)
*
/*
-now we need to use connect() to connect to other socket
- BUT FIRST WE NEED TO SPECIFY AN ADDRESS FOR SOCKET i.e. addr and port no
*/
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("192.168.177.128");
//now time to connect
/*
connect()
arg1: socket
arg2: need to cast our server addfress structure to slightly different struct
from sockaddr_in to sockaddr*
arg3: sizeof the address
connect() returns integer
0 - successful connection
-1 - not successfull
*/
int connection_status;
connection_status = connect(network_socket,(struct sockaddr *) &server_address,sizeof(server_address));
//check for error with the connection
if (connection_status == -1) {
printf("There was an error making a connection to the remote socket \n\n");
}
// recieve data from the server
/*
- recv() function
- first arg: socket
- 2nd arg: address of var where data recived will end up (here it is char array)
- 3rd arg: optional flag parameter give 0
*/
//string to hold data exchanged between client and server
char buffer[256];
printf("Please enter the linux command: ");
//clears the buffer content
bzero(buffer,256);
//get linux command from the console
fgets(buffer,255,stdin);
communication_status = write(network_socket,buffer,strlen(buffer));
//check for write status
if (communication_status < 0) {
perror("Error writing to socket!");
exit(1);
}
//Now getting server response
//clear the buffer
bzero(buffer,256);
communication_status = read(network_socket,buffer,255);
if (communication_status < 0) {
perror("Error reading from socket!");
exit(1);
}
//now we have to print the server response
printf("Server>>: %s\n", buffer);
//close the socket
close(network_socket);
return 0;
}
Server side:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include <stdlib.h>
#include <string.h>
#include<unistd.h>
int readAndParseCmdLine(char **, char **);
int main(int argc, char *argv[]) {
//Checks if the num of argument is 2, if not error message is displayed.
if(argc<2) {
fprintf(stderr,"Num of argument Error");
}
//buffer for data exchange
char buffer[256];
int clientlength, portnum, newSocket;
struct sockaddr_in server_address, cli_addr;
int communication_status,newsockfd;
//create server
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM,0);
if(server_socket == -1) {
perror("Could not connect to socket");
exit(1);
}
//define the server address
bzero((char *) &server_address, sizeof(server_address));
//Coverts the character value to integer for the portno
portnum = atoi(argv[1]);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(portnum);
server_address.sin_addr.s_addr = INADDR_ANY;
//bind the socket to our specified IP and port
//bind is used exactly like we call the connection()
//OS gives resources like port number to Server through bind()
if ( bind(server_socket,(struct sockaddr*) &server_address,sizeof(server_address)) < 0 ) {
perror("Can't bind");
exit(1);
}
/*
listen()
first arg: socket
second arg: backlog (how many connection can be waiting -
essentially for this particular socket at a time - since
we are using this for one client, we can use any number)
*/
listen(server_socket,5);
clientlength = sizeof(cli_addr);
/*
define integer to hold client's socket as once we able to listen() connection
and we can actually start accepting() connections so we can read or write to
clients socket
*/
//The new socket for the client informations
/*
if(newsockfd<1)
{
sleep(1);
}
*/
newSocket = accept(server_socket,(struct sockaddr *) &cli_addr, &clientlength);
if (newSocket < 0) {
perror("ERROR on accept");
exit(1);
}
//Clears the buffer
bzero(buffer,256);
communication_status = read(newSocket,buffer,255);
if (communication_status < 0) {
perror("ERROR reading from socket");
exit(1);
}
//Buffer Stores the msg sent by the client
printf("Here is the entered bash command: %s\n",buffer);
communication_status = write(newSocket,"I got your message",18);
if (communication_status < 0)
{
error("ERROR writing to socket");
}
char *prog;
strcpy(prog, buffer);
char *args[100];
int child_pid;
//Running the Bash Commands
if(readAndParseCmdLine(&prog, args)) {
child_pid =fork();
if(child_pid == 0){ //child part
printf("\n");
execvp(prog, args); // create and run the new process and close the child process
printf("\n");
prog = NULL;
printf("Error in excuting the command- please make sure you type the right syntax.\n");
} else{ //parent part
wait(child_pid);
}
void main();
}
}
//This function reads the linux command form the buffer and parse it
//
int readAndParseCmdLine(char **prog, char **args){
int i =0;
char cmd[100]; //user command
char * temp;
temp = *prog;
if(strcmp(temp,"exit")==0){return 0;} //end program if user type exit.
char *tok;
tok = strtok(temp," \n");
while(tok != NULL){
if(i==0){
prog[0] = tok;
}
args[i] = tok;
printf("\n");
i=i+1;
tok = strtok(NULL, " \n");
}
args[i]=NULL;
return 1;
}
I am trying to create a file transfer program using pthread.h in regards to sockets programming using C.
Both the client and the server source code are implemented but when I run the program it reports "Segmentation fault (core dumped)".
I tried running the program with gdb and it gives me the following error when I input a given file for transfer from the client-side.
Program received signal SIGSEGV, Segmentation fault.
__strcat_sse2_unaligned ()
at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298
298 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
Here is the client source code:
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_PATH_SIZE 1024
void find_file_name(char *name, char *path);
int main()
{
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htons(INADDR_ANY);
client_addr.sin_port = htons(0);
int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket_fd < 0)
{
perror("Create Socket Failed:");
exit(1);
}
else {
perror("Create Socket Done:");
}
if (-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))
{
perror("Client Bind Failed:");
exit(1);
}
else {
perror("Client Bind Success:");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Declare a socket address structure on the server side, and initialize it with the IP address and port on the server side for subsequent connections
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
//Convert the dotted decimal string into a network byte order binary value. This function can handle both IPv4 and IPv6 addresses.
// The first parameter can be AF_INET or AF_INET6:
// The second parameter is a pointer to a dotted decimal string:
// The third parameter is a pointer to the binary value of the converted network byte order.
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)
{
perror("Server IP Address Error:");
exit(1);
}
else {
perror("Server IP Address Success:");
}
server_addr.sin_port = htons(SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
// int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// sockfd: the first parameter is the socket descriptor of the client
// addr: the local address of the current client, a variable of type struct sockaddr_un, a variable of type struct sockaddr_in in different hosts,
// addrlen: indicates the byte length of the local address
// Return value: success flag
if (connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)
{
perror("Can Not Connect To Server IP:");
exit(0);
}
else {
perror("Connected to the Server IP:");
}
char file_path[FILE_PATH_SIZE + 1];
bzero(file_path, FILE_PATH_SIZE + 1);
printf("Input the File Path on Server:\t");
scanf("%s", file_path);
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
strncpy(buffer, file_path, strlen(file_path)>BUFFER_SIZE ? BUFFER_SIZE : strlen(file_path));
//ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//socket: If it is a server, it is the return value of accpet() function, the client is the first parameter in connect() function
// buffer: data written or read
// len: size of data written or read
if (send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
{
perror("Send File Name Failed:");
exit(1);
}
//Convert the target path to a local storage path
char save_path[FILE_PATH_SIZE + 1] = {"/home/madaskalas/Desktop/sockets/pthread/client_files"};
find_file_name(file_path, save_path);
//Try to open the file
FILE *fp = fopen(save_path, "w");
if (NULL == fp)
{
printf("File:\t%s Can Not Open To Write\n", save_path);
exit(1);
}
// Receive data from the server to the buffer
// Each time a piece of data is received, it will be written to the file, looping until the file is received and written
bzero(buffer, BUFFER_SIZE);
int length = 0;
while ((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)
{
if (fwrite(buffer, sizeof(char), length, fp) < length)
{
printf("File:\t%s Write Failed\n", save_path);
break;
}
bzero(buffer, BUFFER_SIZE);
}
// After receiving successfully, close the file and close the socket
printf("Receive File:\t%s From Server IP Successful!\n",save_path);
// close(fp);
close(client_socket_fd);
return 0;
}
void find_file_name(char *name, char *path)
{
char *name_start = NULL;
int sep = '/';
if (NULL == name) {
printf("the path name is NULL\n");
// return NULL;
}
name_start = strrchr(name, sep);
if (NULL == name_start)
{
strcat(path, name_start);
}
else
strcat(path, name_start + 1);
}
Here is the server source code:
#include<stdlib.h>
#include<pthread.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<arpa/inet.h>
#include <unistd.h>
#define SERVER_PORT 8000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 1024
static void Data_handle(void * sock_fd);
int main(void)
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Declare and initialize a server-side socket address structure, socketaddr_in is the address form of the socket in the internet environment
//sockaddr_in (defined in netinet/in.h):
// struct sockaddr_in {
// short int sin_family; /* Address family */
// unsigned short int sin_port; /* Port number */
// struct in_addr sin_addr; /* Internet address */
// unsigned char sin_zero[8]; /* Same size as struct sockaddr */
//};
//struct in_addr {unsigned long s_addr;};
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
//Sa_family: It is an address family, also a masterpiece, a protocol family, generally in the form of "AF_XXX", commonly used are
//AF_INET Arpa (TCP/IP) network communication protocol
//AF_UNIX UNIX domain protocol (file system socket)
//AF_ISO ISO standard protocol
//AF_NS Xerox Network System Agreement
//AF_IPX Novell IPX protocol
//AF_APPLETALK Appletalk DDS
server_addr.sin_family = AF_INET;
//htons is to convert integer variables from host byte order to network byte order, that is, the integer storage method in the address space becomes the high-order byte and is stored at the low address of the memory.
//INADDR_ANY: 0.0.0.0, which refers to the meaning of this machine, that is, it means all the IP of this machine, monitor all the network cards of this machine
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create socket, if successful, return socket descriptor
//1, domain: the protocol domain, also known as the protocol family (family). AF_INET: TCP/IP protocol cluster
//2, type: Specify the socket type. SOCK_STREAM (commonly used) byte stream socket
//3, protocol: As the name implies, it is to specify the protocol. 0: IPPROTO_TCP TCP transmission protocol
int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
if(server_socket_fd < 0)
{
perror("Create Socket Failed:");
exit(1);
}
else {
perror("Create Socket Done:");
}
//int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
//sock: The socket that will be set or get options. level: The protocol layer where the option is located.
//optname: The name of the option to be accessed. optval: For getsockopt(), points to the buffer that returns the option value. optlen: The maximum length of the option value when used as an entry parameter.
// Let SO_REUSEADD==true allow the socket to be bound to an address already in use (see bind()).
int opt = 1;
setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
//bind binds socket and socket address structure
//The three parameters are: socket descriptor, protocol address, and the length of the address
if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
{
perror("Server Bind Failed:");
exit(1);
}
else {
perror("Server Bind Success:");
}
//sockfd: The first parameter is the socket descriptor to be monitored
//backlog: The second parameter is the maximum number of connections that the corresponding socket can queue
//The socket created by the socket() function is an active type by default, and the listen function changes the socket to a passive type, waiting for the client's connection request.
if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))
{
perror("Server Listen Failed:");
exit(1);
}
printf("Socket Listen Successful! Begin to listen!\n");
///////////////////////////////////////////////////////////////////////////////////////////////////////////
while(1)
{
// Define the client's socket address structure
struct sockaddr_in client_addr;
socklen_t client_addr_length = sizeof(client_addr);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//sockfd: The first parameter is the socket descriptor of the server
//addr:, the second parameter is a pointer to struct sockaddr *, used to return the client's protocol address
//addrlen: The third parameter is the length of the protocol address
//Return value: If accpet succeeds, the return value is a brand new description word automatically generated by the kernel, which represents the TCP connection with the returning client.
// Accept the connection request and return a new socket (descriptor). This new socket is used to communicate with the connected client
// The accept function will write the client information to client_addr
int session_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
if(session_fd < 0)
{
perror("Server Accept Failed:");
// break;
}
else {
perror("Server Accept Success:");
}
char client_addr_res[20];
//char *ptr=inet_ntop(AF_INET, &client_addr.sin_addr, client_addr_res, strlen(client_addr_res));
printf("Get Connected with Client:%s ,Opening a new Thread...\n",inet_ntoa(client_addr.sin_addr) );
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, (void *)(&Data_handle), (void *)(&session_fd)) == -1)
{
fprintf(stderr, "pthread_create error!\n");
break; //break while loop
}
}
// Close the socket for monitoring
close(server_socket_fd);
return 0;
}
static void Data_handle(void * fd)
{
int session_fd = *((int *)fd);
// The recv function reads the data into the byte stream through the description word and stores it in the address string
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
if (recv(session_fd, buffer, BUFFER_SIZE, 0) < 0)
{
perror("Server Recieve Data Failed:");
}
char file_name[FILE_NAME_MAX_SIZE + 1];
bzero(file_name, FILE_NAME_MAX_SIZE + 1);
strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer));
printf("Received Filename Successful\n");
// Open the file to read the data and transfer it to the connected client by the file name
FILE *fp = fopen(file_name, "r");
if (NULL == fp)
{
printf("File:%s Not Found\n", file_name);
}
else
{
bzero(buffer, BUFFER_SIZE);//Empty the buffer
int length = 0;
//Read one BUFFER_SIZE data at a time and send it to the client
while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
//ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//socket: If it is a server, it is the return value of the accpet() function, and the client is the first parameter in the connect() function
// buffer: data written or read
// len: size of data written or read
if (send(session_fd, buffer, length, 0) < 0)
{
printf("Send File:%s Failed./n", file_name);
break;
}
bzero(buffer, BUFFER_SIZE);
}
fclose(fp);
printf("Send File:%s To Client Successful!\n", file_name);
}
// int close(int fd) fd: the first parameter of the client's connect() function, the return value of the server's accept()
close(session_fd);
pthread_exit(NULL); //terminate calling thread!
}
Compilation:
gcc -o pthread_client pthread_client.c
gcc -o pthread_server pthread_server.c
I compiled with -g and then use gdb with bt and it produces the following error.
Program received signal SIGSEGV, Segmentation fault. __strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298 298 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory. (gdb) bt #0 __strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298 #1 0x00005555555558b8 in find_file_name (name=0x7fffffffd440 "b.txt", path=0x7fffffffd850 "/home/madaskalas/Desktop/sockets/pthread/client_files") at pthread_client.c:138 #2 0x00005555555556fe in main () at pthread_client.c:96 –
Any help or guidance is greatly appreciated!
Do not cast to/from void*. It happens implicitly.
void Data_handle(void*); pthread_create(..., (void *)(&Data_handle), ...) is plain invalid. Data_handle should return a void*, not void. Calling a void (void*) function via void *(*)(void*) function pointer is invalid.
in server, int session_fd is a local variable inside while(1) block, yet it is passed by pointer to a thread pthread_create(, ... &session_fd) and then thread *((int *)fd); dereferences it. There is a race condition, that session_fd stops existing on the end of loop. Either use dynamic allocation, create a synchronization point to make sure it is dereferenced, or just cast it to/from uintptr_t and pass by value as the void* pointer.
why that bzero all the time? Remove all the calls to bzero maybe except for sockaddr_in initialization. Consider using = {0} there anyway.
strncpy(dest, src, strlen(src) > sizeof(dest) ? sizeof(dest) : strlen(src)) - the strlen(src) > .... is just pointless, cause then the string will not be zero terminated. Also, strncpy does copy up until zero terminating character anyway, it's not memcpy, so why check if yourself anyway. Research strlcpy and strncpy difference, and just use strlcpy(dest, src, sizeof(dest)) to copy a string anyway. Read NOTES section in strncpy man page.
if (NULL == name_start) { strcat(path, name_start); - it's invalid to copy from NULL...
You use strange additional braces in if (-1 == (function())). The ))) are very hard for humans to read in my experience. Consider using if (-1 == function()).
Instead of *((int *)fd) just *(int *)fd.
Try not to do self-explanatory comments.
Overall your code is bad and is filled with bugs and edge cases. Consider rewriting it from scratch and re-studying your material. Interest yourself in helpful code helpers - like -Wall -Wextra -fsanitize=address warnings gcc options, code linters and formatters and valgrind.
I'm trying make the program run multiple threads to it connects to different ports. I successfully made it work on a single thread but not multiple.
Below I have posted the code of what I'm using on XUbuntu.
server.c
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
// File io storing in lof file
#include "server_portLog.h"
// Thread used to create sockets
#include "sockets_pthread.h"
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
// Server port number
//int portNumber = atoi(argv[1]);
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
// Getting all ports from command line parameters and creating a socket for each
int numPorts = argc - 1;
struct port varPorts[numPorts];
pthread_t portsSockets[numPorts];
for (int i = 0; i < numPorts; i++) {
varPorts[i].portNumber = atoi(argv[i + 1]);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&portsSockets[i], &attr, createSocket, &varPorts[i]);
}
// Infinite loop too keep listening even after connection to client closes
while (1) {
// After that all the ports entered have a socket of their own the program runs them parallel together to see if any client tries to connect with one of the ports
for (int i = 0; i <= numPorts; i++) {
pthread_join(&portsSockets[i], NULL);
/* Start listening for the clients (thread blocks) */
if (listen(varPorts[i].sockfd, 5) != 0) {
printf("Error: listen() failed for port: %d \n", varPorts[i].portNumber);
//return 3;
}
// Accepting connection from client & creating socket with that client data
newsockfd = accept(varPorts[i].sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0) {
printf("Error: accept() failed for port: %d \n", varPorts[i].portNumber);
//return 4;
}
/* To send receive data */
// Clearing buffer
memset(buffer, 0, BUFFER_SIZE);
// Show data received from client
num_bytes = recv(newsockfd, buffer, BUFFER_SIZE-1, 0);
if (num_bytes < 0) {
printf("Error: recv() failed for port: %d \n", varPorts[i].portNumber);
//return 5;
}
// Checking version of server if LOGFILE it creates a file to store the ports
#if defined LOGFILE
// Checking if user wrote a fileName for the logs or going to use the default log file
if (argc == 3) {
char *textFile = argv[argc-1];
serverLogFile_Custom(buffer, textFile);
}
else {
serverLogFile_Defualt(buffer);
}
#else
// Print the port numbers that connect to server
printf("Received: Client using port- %s to connect \n", buffer);
#endif
// Closing connection with client
close(newsockfd);
}
}
return 0;
}
Sockets_pthreads.h
#include <pthread.h>
struct port {
int portNumber;
int sockfd;
};
void* createSocket(void* portNumber) {
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
//char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
struct port *portStruct = (struct port*) portNumber;
// Creating a new socket with ip-Protocol_tcp
// Parameters: Internet-domain, socket-stream, TCP-protocol
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
printf("Error: Failed to open socket for port: %d \n", portStruct->portNumber);
//return 1;
}
// Setting all bits in padding-field to 0
memset(&serv_addr, 0, sizeof(serv_addr));
// Initializing socket in sockaddr_in (stucture)
serv_addr.sin_family = AF_INET; // Seting family-Internet
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portStruct->portNumber); // Setting portNum (passed in command line)
// Binding the address-structure to the socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("Error: bind() failed for port: %d \n", portStruct->portNumber);
//return 2;
}
// Geting sockfd
portStruct->sockfd = sockfd;
pthread_exit(0);
}
Problem is not clear what needs to be implemented. If various ports sockets have to accept, then it has to happen in thread function as well as recv call. In server function there are accept and recv calls which are blocking by default.
The main function should wait for connections. Upon receiving a request from the client, you create a thread that will handle this specific connection. So you will create the threads in the loop, meaning, you can theoretically have an infinite number of threads.
However, you can add a little logic to limit the number of threads that are existing at a particular time (thread pool).
So your main loop can look like this:
while (1) {
// accept: wait for a connection request
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t *) &clientlen);
if (childfd < 0){
fprintf(stderr,"ERROR on accept");
continue;
}
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL){
fprintf(stderr,"ERROR on inet_ntoa\n");
continue;
}
fprintf(stdout,"server established connection with client\n");
pthread_t new_thread;
newSock = malloc(1);
*newSock = childfd;
if( pthread_create( &new_thread , NULL , server_thread , (void*) newSock) < 0){
bzero(logMsg, MAXSTRING);
sprintf(logMsg, "Thread for connection %d could not be created",childfd);
fprintf(stderr, "%s\n", logMsg);
continue;
}
fprintf(stdout, "thread created for connection %d\n", childfd);
}
The server_thread function could look like:
void *server_thread(void* clientSock){
int childfd = *(int*)clientSock;
char buf[MAXLINE]; // message buffer
int n; // message byte size
char logMsg[MAXSTRING];
size_t siz_failresp;
// read: read input string from the client
bzero(buf, MAXLINE);
n = (int) read(childfd, buf, MAXLINE);
if (n < 0){
sprintf(logMsg, "ERROR reading from socket");
fprintf(stderr,"%s", logMsg);
close(childfd);
fprintf(stdout, "Client %d disconnected \n=================\n", childfd);
//Free the socket pointer
free(clientSock);
return NULL;
}
// else, do processing of data received...
// ...................
}
There may be unused variables here above... I just got this code from one of my projects, just removing parts that do not concern you :-)
Hope it helps
I try to create a function to open a socket (i will have multiple socket in the future) called libf_build_udp_socket. But when it comes to bind i got the error cannot assign requested address and if i bypass this bind i got an error when sending a cmd.
If i don't use my function and integrate directly the code in my main, it works perfectly.
For the explanation i have a computer under linux that have to send cmd and received log from different equipment such as signal receiver...
Here is my full code, so maybe you will better understand my goals.
/* Standard Linux headers */
#include <stdio.h> //printf
#include <string.h> //memset
#include <stdlib.h> //exit(0);
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/times.h>
#include <unistd.h>
#include <errno.h>
/* DEFINE */
#define IP_RX "192.168.0.10" //notre IP=192.168.0.5
#define BUFFLEN 1024 //Max length of buffer
#define PORT_RX 3000 //The port on which to send data
unsigned short int libf_build_udp_socket(int * udp_socket, char * server_address, unsigned short int udp_port);
int main (void)
{
/*
** Definition of the local variables.
*/
//SOCKET
struct sockaddr_in addr_rx;
int serv_len_rx=sizeof(addr_rx);
int socket_fd_rx;
unsigned short int socketStatus; /* Socket return status */
//FD
fd_set readfds;
//BUFFER & CMD
char recepbuff[BUFFLEN];
char cmd[BUFFLEN], cmd_final[BUFFLEN];
//OTHER
int i, recv;
char choice;
int loop=1;
//TIMEOUT STRUCT
struct timeval tv;
tv.tv_sec=0; /*timeout de 0sec*/
tv.tv_usec=1000; //NE MARCHE PAS SI =0
/*
** Initialisation of the local variables.
*/
memset(recepbuff, '0' ,sizeof(recepbuff)); /*pareil que bzero*/
i=0;
/*
** Creating the socket
** call socket (it creates an endpoint for communication and
** returns the socket descriptor.
** To create an UDP socket here are the param
** The protocol family should be AF_INET
** The protocol type is SOCK_DGRAM
** The protocol should beset to default ie
** DEF_PROTOCOL wich is default so 0. );
*/
//OPENING AND SETTING SOCKET RX
socketStatus = libf_build_udp_socket(&socket_fd_rx, IP_RX, PORT_RX);
if (socketStatus>0)
{
printf("Could not create the socket, code error %d\n", socketStatus);
return 0;
}
/* Messaging*/
while(1)
{
printf ("\n//Boucle %d\n", i);
//clear the buffer by filling null, it might have previously received data
memset(recepbuff, '\0' ,sizeof(recepbuff));
loop=1;
//preparing cmd
printf("Enter command :");
fgets(cmd, sizeof(cmd) , stdin);
snprintf(cmd_final, sizeof (cmd_final), cmd, "\r\n"); /*adding 0d 0a to the cmd*/
//send cmd
if ( (sendto(socket_fd_rx , cmd_final, BUFFLEN , 0 , (struct sockaddr *)&addr_rx, serv_len_rx) ) < 0 )
{
perror("ERROR > send cmd failed to wass : ");
return 0;
}
else
{
printf( "cmd send to %s:%d\n" ,inet_ntoa(addr_rx.sin_addr), ntohs(addr_rx.sin_port) );
}
//printf("\n... waiting answer from %s:%d ... \n" ,inet_ntoa(addr_rx.sin_addr), ntohs(addr_rx.sin_port) );
//strcpy(recepbuff, "whileloop");
//try to receive some data, this is a blocking call
while(loop)
{
memset(recepbuff, '\0' ,sizeof(recepbuff)); //empty buffer
FD_ZERO(&readfds);
FD_SET(socket_fd_rx, &readfds); //set testing for rx
select(socket_fd_rx+1, &readfds, NULL, NULL, &tv); //block until cmd becomes available
if(FD_ISSET(socket_fd_rx, &readfds)) //input rx available
{
//printf("Data to be read \n");
recvfrom( socket_fd_rx, recepbuff , BUFFLEN, 0, (struct sockaddr *)&addr_rx, &serv_len_rx); //recep
printf("[=> Réponse : %s\n", recepbuff);
}
else
{
loop=0;
}
}
printf(".... Réponse done from %s:%d .... \n",inet_ntoa(addr_rx.sin_addr),ntohs(addr_rx.sin_port) );
i++;
}
close(socket_fd_rx);
return 0;
}
//FONCTIONS
//OPENING 1 SETTING A SOCKET
/** libf_build_udp_socket
*
* This function creates an UDP socket.
*
* \param udp_socket socket identifier
* \param server_address IP destination address
* \param udp_port Destination UDP port
* \param server_flag TRUE to bind socket on UDP port
*
* \return 0 if successful; error code otherwise
*/
unsigned short int libf_build_udp_socket(int * udp_socket, char * server_address, unsigned short int udp_port)
{
/*
** Defining of the local variables.
*/
struct sockaddr_in serv_addr; /* Server Socket address structure*/
short int status = 0; /* internal status return*/
unsigned short int return_status = 0; /* the returnes status value */
/*
** creating the socket ;
** call socket (it creates an endpoint for communication and
** returns the socket
** descriptor. To create an UDP socket
** the parameter family is set
** to AF_INET, the type to SOCK_DGRAM, and
** the protocol to
** DEF_PROTOCOL. The socket is a global variable.);
*/
*udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (*udp_socket < 0)
{
return_status = 1;
}
else
{
status = 1; //for future check
if (status >= 0)
{
/*
** reset the serv_addr variable
*/
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
/*
** set the sockname.sin_addr.s_addr to server address;
** sockname.sin_addr.s_addr = htonl(server address);
** set the sockname field sockname.sin_port to the used port number;
** sockname.sin_port = htons (udp port);
*/
serv_addr.sin_addr.s_addr = inet_addr(server_address);
serv_addr.sin_port = htons(udp_port);
/*
** Bind this socket to a name;
** call bind (it assigns a name or address to an unnamed socket.
** When a socket is created with socket it exists in
** a name space (address family) but has no name assigned.
** The bind requests the name, be assigned to the socket);
** If (return status signal an error)
** {
** set to return variable to error
** }
*/
status = bind(*udp_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (status < 0)
{
printf("bind failed with %s", strerror(errno));
return_status = 2;
}
}
else
{
return_status = 3;
}
}
/*
** return status;
*/
return return_status;
}
Maybe i'm missing something essential in socket programming, i made a lot of research and try different things but it still doesn't want to work ! I would appreciate some help ! Thank you !