Notez que j'ai eu du mal à communiquer avec le serveur Ruby TCP et le client C.
En conséquence, le problème était que les unités de la quantité de données apparentes que Ruby et C envoyaient et recevaient dans le flux étaient différentes. Par conséquent, nous avons implémenté la fonction sputs et la fonction sgets qui encapsulent l'écriture et la lecture en C afin qu'ils puissent communiquer dans la même unité que Ruby.
L'environnement est
est.
C'est un serveur qui démarre la communication et renvoie la chaîne de caractères reçue du client presque telle quelle. Répétez ceci 5 fois pour terminer.
server.rb
require 'socket'
#Démarrez le serveur sur le port 20000
server = TCPServer.open(20000)
#Accepter la communication
sock = server.accept
5.times do
#Recevez une ligne du tampon.(Recevez jusqu'au saut de ligne)
line = sock.gets.chomp
#Affiché sur la console. S'il est p, il est également nul\Il est affiché sous la forme x00.
p line
#Revenir. À la fin\n est ajouté.
sock.puts("you sent <<<#{line}>>>.")
end
#Déconnecter la communication
sock.close
Implémentez les fonctions sputs et sgets pour les get et les put de ruby.
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define RECV_SIZE (10000)
#define SEND_SIZE (10000)
/*
*Récupère une ligne dans le tampon.(get string from stream)
*S'il n'y a pas de données pour une ligne dans le tampon, attendez.
*/
char* sgets(int sd, char* line) {
//La partie retirée avant le dernier saut de ligne
static char* read_buf = NULL;
if (read_buf == NULL) {
read_buf = malloc(sizeof(char) * RECV_SIZE);
read_buf[0] = '\0';
}
while (1) {
int e;
if (strlen(read_buf) != (e = strcspn(read_buf, "\n"))) {
//Initialiser la ligne
memset(line, '\0', sizeof(char) * strlen(line));
//Copier une ligne en ligne
strncpy(line, read_buf, (e + 1) - 0);
//Lisez la ligne suivante_Copier depuis le début de buf
strcpy(read_buf, strchr(read_buf, '\n') + 1);
break;
}
//Initialiser et préparer une baie pour la réception
char r[RECV_SIZE] = { 0 };
//Reçoit la quantité de char qui vient d'être envoyée du tampon.(Aucun NULL de fin)
if (read(sd, r, sizeof(r) * RECV_SIZE) < 0) {
perror("recv");
fflush(0);
return NULL;
}
//Accumulez les données lues.
strcat(read_buf, r);
}
return line;
}
/*
*Envoyez une ligne.(put string to stream)
*À la fin"\n"Est ajouté.
*/
void sputs(int sd, char* str) {
char* send_str = malloc(sizeof(char) *(strlen(str) + 2));
memset(send_str, '\0', sizeof(char) *(strlen(str) + 2));
strcat(send_str, str);
send_str[strlen(str)] = '\n';
if (write(sd, send_str, sizeof(char) * strlen(send_str)) < 0) {
perror("send");
return;
}
free(send_str);
}
int main(int argc, char *argv[]) {
int sd; //Variables de création de sockets
struct sockaddr_in addr; //Variables pour la connexion au serveur
char *recv[sizeof(char) * RECV_SIZE] = {0};
//Créer un socket pour IPv4 TCP
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
//Définissez l'adresse de destination et le numéro de port
addr.sin_family = AF_INET;
addr.sin_port = htons(20000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//Connexion serveur (pour TCP, vous devez établir une connexion)
connect(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
char* strs[5] = {"abcde", "fg", "hijklmn", "opqrs", "tuvwxyz"};
for(int i = 0; i < 5; i++) {
//Envoyez une ligne. À la fin\n est ajouté.
sputs(sd, strs[i]);
//Obtenez une ligne.
sgets(sd, recv);
//afficher
printf("I recived <<<%s>>>\n", recv);
}
//Fermer la prise
close(sd);
return 0;
}
Soyez prudent avec la fonction de lecture utilisée dans sgets. Le contenu du tampon est écrit dans r
avec read (sd, r, sizeof (r) * RECV_SIZE)
, mais la fonction read
ne passe pas bien la fin de la chaîne de caractères, mais 1 octet. Écrivez le point que vous avez reçu à chaque fois. De plus, null n'est pas ajouté à la fin de l'écriture. Par conséquent, il est recommandé de remplir r avec null à chaque fois.
Notez également la fonction d'écriture utilisée dans les sputs. Si vous utilisez write (sd, send_str, sizeof (char) * strlen (send_str)
avec un grand nombre de 3ème arguments et le définissez sur SEND_SIZE
, SEND_SIZE octets sera envoyé quelle que soit la longueur de la chaîne dans le 2ème argument. Il semble que la partie manquante soit remplie avec NULL.
À propos, l'implémentation qui ne fonctionne pas bien est la suivante.
client.c(Mauvais exemple)
int main(int argc, char *argv[]) {
int sd; //Variables de création de sockets
struct sockaddr_in addr; //Variables pour la connexion au serveur
char *recv[sizeof(char) * RECV_SIZE] = {0};
//Créer un socket pour IPv4 TCP
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return -1;
}
//Définissez l'adresse de destination et le numéro de port
addr.sin_family = AF_INET;
addr.sin_port = htons(20000);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//Connexion serveur (pour TCP, vous devez établir une connexion)
connect(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
char* strs[5] = {"abcde", "fg", "hijklmn", "opqrs", "tuvwxyz"};
for(int i = 0; i < 5; i++) {
//Envoyez une ligne.
write(sd, strs[i], SEND_SIZE);
//Obtenez une ligne.
read(sd, recv, RECV_SIZE);
//afficher
printf("I recived <<<%s>>>\n", recv);
}
//Fermer la prise
close(sd);
return 0;
}
Ecrire en lecture et en écriture avec la même sensation get et met que Ruby échouera.
$ ruby server.rb
$ gcc -O2 -o client client.c
$ ./clinet
Du côté serveur
"abcde\n"
"fg\n"
"hijklmn\n"
"opqrs\n"
"tuvwxyz\n"
Côté client
I recived <<<you sent <<<abcde>>>.
>>>
I recived <<<you sent <<<fg>>>.
>>>
I recived <<<you sent <<<hijklmn>>>.
>>>
I recived <<<you sent <<<opqrs>>>.
>>>
I recived <<<you sent <<<tuvwxyz>>>.
>>>
En C, il ne se convertit pas en une chaîne de caractères comme Ruby, j'ai donc dû faire attention au traitement octet par octet. Probablement, si la communication TCP est effectuée entre d'autres langues, divers problèmes sont susceptibles de se produire en raison de la différence dans la gestion de la communication.
Recommended Posts