=====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");
}
[[https://social.msdn.microsoft.com/Forums/en-US/2202d113-212d-420d-9e7b-11268de9ce90/win32-tcp-connect-timeout|Win32: TCP connect timeout]] {{ :lang:c:net:win32_tcp_connect_timeout_27_01_2023_15_32_49_.html |Archive du 24/08/2018 le 27/01/2023}}
====send/recv sous Linux====
TODO. recv en non bloquant.
{{:lang:c:net:tcp_ip_socket_diagram.png|Diagramme de séquence TCP}}
[[https://www.bogotobogo.com/cplusplus/sockets_server_client.php|SOCKETS - SERVER & CLIENT - 2020]] {{ :lang:c:net:c_tutorial_sockets_-_server_client_-_2020_2020-04-26_10_45_46_pm_.html |Archive du 2020 le 26/04/2020}}
[[https://www.bogotobogo.com/cplusplus/sockets_server_client_2.php|SOCKETS - SERVER & CLIENT 2 - 2020]] {{ :lang:c:net:c_tutorial_sockets_-_server_client_2_-_2020_2020-04-26_10_53_42_pm_.html |Archive du 2020 le 26/04/2020}}
[[https://www.bogotobogo.com/cplusplus/sockets_server_client_3.php|SOCKETS - SERVER & CLIENT 3 - 2020]] {{ :lang:c:net:c_tutorial_sockets_-_server_client_3_-_2020_2020-04-26_10_55_01_pm_.html |Archive du 2020 le 26/04/2020}}
[[https://www.binarytides.com/server-client-example-c-sockets-linux/|Server and client example with C sockets on Linux]] {{ :lang:c:net:server_and_client_example_with_c_sockets_on_linux_binarytides_2020-04-26_10_47_54_pm_.html |Archive du 27/11/2012 le 26/04/2020}}
[[http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/|Programming UNIX Sockets in C - Frequently Asked Questions]] {{ lang:c:net:unix-socket-faq.zip |Archive FAQ}} {{ lang:c:net:examples.tar.gz |Archive Source}}
[[https://vincent.bernat.ch/fr/blog/2014-tcp-time-wait-state-linux|TCP TIME-WAIT & les serveurs Linux à fort trafic]] {{ :lang:c:net:tcp_time-wait_les_serveurs_linux_a_fort_trafic_⁕_vincent_bernat_2020-04-26_10_49_25_pm_.html |Archive du 24/02/2014 le 26/04/2020}}
===Serveur===
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
// 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===
#include
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#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