Outils pour utilisateurs

Outils du site


lang:c:net:client_serveur

TCP

connect sous Windows

Pour ne pas avoir de connect bloquant et maitriser le timeout, on peut utiliser le code suivant :

int error = -1;
int len = sizeof(int);
timeval tm;
fd_set set;
unsigned long ul = 1;
ioctlsocket(Socket, FIONBIO, &ul);  // set as non-blocking
bool ret = false;
if (connect(Socket, (struct sockaddr *)&ServerAddress,
      sizeof(ServerAddress)) == -1) {
  tm.tv_sec = 10;  // set the timeout. 10s
  tm.tv_usec = 0;
  FD_ZERO(&set);
  FD_SET(Socket, &set);
 
  if (select(Socket + 1, NULL, &set, NULL, &tm) > 0) {
    getsockopt(Socket, SOL_SOCKET, SO_ERROR, (char *)&error,
           /*(socklen_t *)*/ &len);
    if (error == 0)
      ret = true;
    else
      ret = false;
  } else
    ret = false;
} else
  ret = true;
 
ul = 0;
ioctlsocket(Socket, FIONBIO, &ul);  // set as blocking
if (!ret) {
  closesocket(Socket);
  fprintf(stderr, "Cannot Connect the server!/n");
}

Win32: TCP connect timeout Archive du 24/08/2018 le 27/01/2023

send/recv sous Linux

Serveur

serveur.c
#define _GNU_SOURCE
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
 
// the thread function
void *connection_handler(void *socket_desc);
 
int main(int argc, char *argv[]) {
  int socket_desc, client_sock, c, *new_sock;
  struct sockaddr_in server, client;
 
  // Create socket
  socket_desc = socket(AF_INET, SOCK_STREAM, 0);
  if (socket_desc == -1) {
    printf("Could not create socket");
  }
  puts("Socket created");
 
  // Prepare the sockaddr_in structure
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = INADDR_ANY;
  server.sin_port = htons(8888);
 
  // Bind
  if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
    // print the error message
    perror("bind failed. Error");
    return 1;
  }
  puts("bind done");
 
  // Listen
  listen(socket_desc, 3);
 
  // Accept and incoming connection
  puts("Waiting for incoming connections...");
  c = sizeof(struct sockaddr_in);
  while ((client_sock = accept4(socket_desc, (struct sockaddr *)&client,
                                (socklen_t *)&c, 0))) {
    puts("Connection accepted");
 
    pthread_t sniffer_thread;
    new_sock = (int *)malloc(sizeof(int));
    *new_sock = client_sock;
 
    if (pthread_create(&sniffer_thread, NULL, connection_handler,
                       (void *)new_sock) < 0) {
      perror("could not create thread");
      return 1;
    }
 
    // Now join the thread , so that we dont terminate before the thread
    // pthread_join( sniffer_thread , NULL);
    puts("Handler assigned");
  }
 
  if (client_sock < 0) {
    perror("accept failed");
    return 1;
  }
 
  return 0;
}
 
/*
 * This will handle connection for each client
 * */
void *connection_handler(void *socket_desc) {
  // Get the socket descriptor
  int sock = *(int *)socket_desc;
  int read_size;
  char *message, client_message[2000];
 
  // Send some messages to the client
  message = "Greetings! I am your connection handler\n";
  write(sock, message, strlen(message) + 1);
 
  message = "Now type something and i shall repeat what you type \n";
  write(sock, message, strlen(message) + 1);
 
  // Receive a message from client
  while ((read_size = recv(sock, client_message, 2000, 0)) > 0) {
    // Send the message back to client
    write(sock, client_message, strlen(client_message) + 1);
  }
 
  if (read_size == 0) {
    puts("Client disconnected");
    fflush(stdout);
  } else if (read_size == -1) {
    perror("recv failed");
  }
 
  // Free the socket pointer
  free(socket_desc);
 
  return 0;
}

Client

client.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
 
int main(int argc, char *argv[]) {
  int sock;
  struct sockaddr_in server;
  char message[1000], server_reply[2000];
 
  // Create socket
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock == -1) {
    printf("Could not create socket");
  }
  puts("Socket created");
 
  server.sin_addr.s_addr = inet_addr("127.0.0.1");
  server.sin_family = AF_INET;
  server.sin_port = htons(8888);
 
  // Connect to remote server
  if (connect(sock, (struct sockaddr *)(&server), sizeof(server)) < 0) {
    perror("connect failed. Error");
    return 1;
  }
 
  puts("Connected\n");
 
  // keep communicating with server
  while (1) {
    printf("Enter message : ");
    scanf("%s", message);
 
    // Send some data
    if (send(sock, message, strlen(message) + 1, 0) < 0) {
      puts("Send failed");
      return 1;
    }
 
    // Receive a reply from the server
    if (recv(sock, server_reply, 2000, 0) < 0) {
      puts("recv failed");
      break;
    }
 
    puts("Server reply :");
    puts(server_reply);
  }
 
  close(sock);
  return 0;
}

sendmsg/recvmsg sous Linux

Transfert d'un file descripteur via socket Unix.

Il faut passer par un fichier temporaire. Je n'ai pas réussi à transposer le code par des ports TCP/IP.

Serveur

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
 
#define SOCK_PATH "/tmp/usocket"
 
int send_msg_to_client(int socketfd, int fd) {
 
  struct msghdr msg;
  struct iovec iov;
  int s;
  char buf[CMSG_SPACE(sizeof(fd))];
 
  memset(&msg, 0, sizeof(msg));
  memset(&iov, 0, sizeof(iov));
 
  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  iov.iov_base = "";
  iov.iov_len = 1;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_control = buf;
  msg.msg_controllen = sizeof(buf);
  msg.msg_flags = 0;
 
  struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_RIGHTS;
  cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
 
  memmove(CMSG_DATA(cmsg), &fd, sizeof(fd));
 
  msg.msg_controllen = CMSG_SPACE(sizeof(fd));
 
  s = sendmsg(socketfd, &msg, 0);
 
  if (s < 0) {
    perror("sendmsg");
    return 0;
  }
 
  return s;
}
 
int main(int argc, char *argv[]) {
  int s, s2, len, slen;
  socklen_t t;
  struct sockaddr_un local, remote;
 
  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }
 
  local.sun_family = AF_UNIX;
  strcpy(local.sun_path, SOCK_PATH);
 
  unlink(local.sun_path);
 
  len = strlen(local.sun_path) + sizeof(local.sun_family);
  if (bind(s, (struct sockaddr *)&local, len) == -1) {
    perror("bind");
    exit(1);
  }
 
  if (listen(s, 5) == -1) {
    perror("listen");
    exit(1);
  }
 
  printf("Waiting for a connection...\n");
 
  t = sizeof(remote);
  if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
    perror("accept");
    exit(1);
  }
 
  printf("Connected.\n");
 
  int fd = open("./z7.c", O_RDONLY);
  if (fd < 0)
    printf("Parent Failed to open file %s for reading\n", "./z7.c");
 
  slen = send_msg_to_client(s2, fd);
 
  if (slen < 0)
    perror("send");
 
  printf("sent data length: %d\n", slen);
 
  close(s2);
 
  return 0;
}

Client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
 
#define SOCK_PATH "/tmp/usocket"
 
int recv_msg_from_server(int socketfd) {
 
  struct msghdr msg = {0};
 
  /* On Mac OS X, the struct iovec is needed, even if it points to minimal data
   */
  char m_buffer[1];
  struct iovec io = {.iov_base = m_buffer, .iov_len = sizeof(m_buffer)};
  msg.msg_iov = &io;
  msg.msg_iovlen = 1;
 
  char c_buffer[256];
  msg.msg_control = c_buffer;
  msg.msg_controllen = sizeof(c_buffer);
 
  if (recvmsg(socketfd, &msg, 0) < 0)
    printf("Child Failed to receive message\n");
 
  struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
 
  printf("Child About to extract fd\n");
  int fd;
  memmove(&fd, CMSG_DATA(cmsg), sizeof(fd));
  printf("Child Extracted fd %d\n", fd);
 
  return fd;
}
 
int main(void) {
  int s, len, slen;
  struct sockaddr_un remote;
 
  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }
 
  printf("Trying to connect...\n");
 
  remote.sun_family = AF_UNIX;
  strcpy(remote.sun_path, SOCK_PATH);
  len = strlen(remote.sun_path) + sizeof(remote.sun_family);
 
  if (connect(s, (struct sockaddr *)&remote, len) == -1) {
    perror("connect");
    exit(1);
  }
 
  printf("Connected.\n");
 
  slen = recv_msg_from_server(s);
 
  char buffer[256];
  int nbytes;
  if ((nbytes = read(slen, buffer, sizeof(buffer))) > 0) {
    printf("Child read: [[%.*s]]\n", nbytes, buffer);
  }
 
  close(s);
 
  return 0;
}

UDP

TODO

lang/c/net/client_serveur.txt · Dernière modification : 2023/01/27 15:35 de root