Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision Next revision Both sides next revision | ||
workshop:sockets [2010-09-29 19:47] equinox angelegt |
workshop:sockets [2010-09-29 19:59] equinox |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Vortrag/Workshop Einführung in Einführung Unix Socket Programmierung ====== | + | ====== Vortrag/Workshop Einführung in Unix Socket Programmierung ====== |
* by Christian Pointner | * by Christian Pointner | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===== Beispielcode ===== | ||
+ | |||
+ | Es folgen ein paar simple Beispielprogramme die die Verwendung von Sockets unter Unix zeigen. Alle Beispiele und ein kleines Makefile können auch direkt per unten stehendem Link heruntergeladen werden: | ||
+ | |||
+ | {{workshops:socket-examples.tar.gz|socket-examples.tar.gz}} | ||
+ | |||
+ | Es folgt noch der Code für einen sehr simplen Chat Server anhand dessen die Verwendung des Resolvers (DNS etc.) gezeigt wird. | ||
+ | |||
+ | ==== Beispiel: udpclient ==== | ||
+ | |||
+ | <file> | ||
+ | /* | ||
+ | * udpclient | ||
+ | * | ||
+ | * This is a very basic UDP client example to show the usage of | ||
+ | * sockets. | ||
+ | * | ||
+ | * Copyright (C) 2010 Christian Pointner <equinox@realraum.at> | ||
+ | * | ||
+ | * udpclient is free software: you can redistribute it and/or modify | ||
+ | * it under the terms of the GNU General Public License as published by | ||
+ | * the Free Software Foundation, either version 3 of the License, or | ||
+ | * any later version. | ||
+ | * | ||
+ | * udpclient is distributed in the hope that it will be useful, | ||
+ | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
+ | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
+ | * GNU General Public License for more details. | ||
+ | * | ||
+ | * You should have received a copy of the GNU General Public License | ||
+ | * along with udpclient. If not, see <http://www.gnu.org/licenses/>. | ||
+ | */ | ||
+ | |||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <unistd.h> | ||
+ | #include <errno.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | #include <sys/types.h> | ||
+ | #include <sys/socket.h> | ||
+ | |||
+ | #include <arpa/inet.h> | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | if(argc <= 2) { | ||
+ | fprintf(stderr,"too few arguments\n"); | ||
+ | exit(1); | ||
+ | } | ||
+ | printf("starting UDP Client\n"); | ||
+ | |||
+ | int sock = socket(AF_INET, SOCK_DGRAM, 0); | ||
+ | if(sock < 0) { | ||
+ | perror("socket() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | | ||
+ | struct sockaddr_in local_addr; | ||
+ | memset((char *) &local_addr, 0, sizeof(local_addr)); | ||
+ | local_addr.sin_family = AF_INET; | ||
+ | local_addr.sin_port = htons(4321); | ||
+ | local_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
+ | |||
+ | if(bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr))==-1) { | ||
+ | perror("bind() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | struct sockaddr_in remote_addr; | ||
+ | int alen, len; | ||
+ | alen = sizeof(remote_addr); | ||
+ | remote_addr.sin_family = AF_INET; | ||
+ | remote_addr.sin_port = htons(atoi(argv[2])); | ||
+ | if (inet_aton(argv[1], &remote_addr.sin_addr)==0) { | ||
+ | perror("inet_aton() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | uint8_t buffer[1500]; | ||
+ | for (;;) { | ||
+ | if((len = read(0, buffer, 1500))==-1) { | ||
+ | perror("read() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | if((len = sendto(sock, buffer, len, 0, (struct sockaddr *)&remote_addr, alen))==-1) { | ||
+ | perror("sendto() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | close(sock); | ||
+ | | ||
+ | printf("exiting UDP Client\n"); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </file> | ||
+ | ==== Beispiel: udpserver ==== | ||
+ | |||
+ | <file> | ||
+ | /* | ||
+ | * udpserver | ||
+ | * | ||
+ | * This is a very basic UDP client example to show the usage of | ||
+ | * sockets. | ||
+ | * | ||
+ | * Copyright (C) 2010 Christian Pointner <equinox@realraum.at> | ||
+ | * | ||
+ | * udpserver is free software: you can redistribute it and/or modify | ||
+ | * it under the terms of the GNU General Public License as published by | ||
+ | * the Free Software Foundation, either version 3 of the License, or | ||
+ | * any later version. | ||
+ | * | ||
+ | * udpserver is distributed in the hope that it will be useful, | ||
+ | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
+ | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
+ | * GNU General Public License for more details. | ||
+ | * | ||
+ | * You should have received a copy of the GNU General Public License | ||
+ | * along with udpserver. If not, see <http://www.gnu.org/licenses/>. | ||
+ | */ | ||
+ | |||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <unistd.h> | ||
+ | #include <errno.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | #include <sys/types.h> | ||
+ | #include <sys/socket.h> | ||
+ | |||
+ | #include <arpa/inet.h> | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | printf("starting UDP Server\n"); | ||
+ | |||
+ | int sock = socket(AF_INET, SOCK_DGRAM, 0); | ||
+ | if(sock < 0) { | ||
+ | perror("socket() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | | ||
+ | struct sockaddr_in local_addr; | ||
+ | memset((char *) &local_addr, 0, sizeof(local_addr)); | ||
+ | local_addr.sin_family = AF_INET; | ||
+ | local_addr.sin_port = htons(1234); | ||
+ | local_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
+ | |||
+ | if(bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr))==-1) { | ||
+ | perror("bind() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | struct sockaddr_in remote_addr; | ||
+ | int alen, len; | ||
+ | alen = sizeof(remote_addr); | ||
+ | uint8_t buffer[1500]; | ||
+ | for (;;) { | ||
+ | if((len = recvfrom(sock, buffer, 1500, 0, (struct sockaddr *)&remote_addr, &alen))==-1) { | ||
+ | perror("recvfrom() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | printf("Received %d Bytes from %s:%d\n", len, inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port)); | ||
+ | } | ||
+ | |||
+ | close(sock); | ||
+ | | ||
+ | printf("exiting UDP Server\n"); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | ==== Beispiel: tcpclient ==== | ||
+ | |||
+ | <file> | ||
+ | /* | ||
+ | * tcpclient | ||
+ | * | ||
+ | * This is a very basic TCP client example to show the usage of | ||
+ | * sockets. | ||
+ | * | ||
+ | * Copyright (C) 2010 Christian Pointner <equinox@realraum.at> | ||
+ | * | ||
+ | * tcpclient is free software: you can redistribute it and/or modify | ||
+ | * it under the terms of the GNU General Public License as published by | ||
+ | * the Free Software Foundation, either version 3 of the License, or | ||
+ | * any later version. | ||
+ | * | ||
+ | * tcpclient is distributed in the hope that it will be useful, | ||
+ | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
+ | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
+ | * GNU General Public License for more details. | ||
+ | * | ||
+ | * You should have received a copy of the GNU General Public License | ||
+ | * along with tcpclient. If not, see <http://www.gnu.org/licenses/>. | ||
+ | */ | ||
+ | |||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <unistd.h> | ||
+ | #include <errno.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | #include <sys/types.h> | ||
+ | #include <sys/socket.h> | ||
+ | |||
+ | #include <arpa/inet.h> | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | if(argc <= 2) { | ||
+ | fprintf(stderr,"too few arguments\n"); | ||
+ | exit(1); | ||
+ | } | ||
+ | printf("starting TCP Client\n"); | ||
+ | |||
+ | int sock = socket(AF_INET, SOCK_STREAM, 0); | ||
+ | if(sock < 0) { | ||
+ | perror("socket() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | | ||
+ | struct sockaddr_in remote_addr; | ||
+ | remote_addr.sin_family = AF_INET; | ||
+ | remote_addr.sin_port = htons(atoi(argv[2])); | ||
+ | if (inet_aton(argv[1], &remote_addr.sin_addr)==0) { | ||
+ | perror("inet_aton() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | if(connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr))==-1) { | ||
+ | perror("connect() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | int len; | ||
+ | uint8_t buffer[1500]; | ||
+ | for (;;) { | ||
+ | if((len = read(0, buffer, 1500))==-1) { | ||
+ | perror("read() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | int offset = 0; | ||
+ | int wlen; | ||
+ | for(;;) { | ||
+ | wlen = send(sock, &buffer[offset], len - offset, 0); | ||
+ | if(wlen == -1) { | ||
+ | if(errno != EINTR) { | ||
+ | perror("write() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | wlen = 0; | ||
+ | } | ||
+ | |||
+ | offset += wlen; | ||
+ | if(offset+1 >= len) | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | close(sock); | ||
+ | | ||
+ | printf("exiting TCP Client\n"); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | ==== Beispiel: tcpserver ==== | ||
+ | |||
+ | <file> | ||
+ | /* | ||
+ | * tcpserver | ||
+ | * | ||
+ | * This is a very basic TCP server example to show the usage of | ||
+ | * sockets. | ||
+ | * | ||
+ | * Copyright (C) 2010 Christian Pointner <equinox@realraum.at> | ||
+ | * | ||
+ | * tcpserver is free software: you can redistribute it and/or modify | ||
+ | * it under the terms of the GNU General Public License as published by | ||
+ | * the Free Software Foundation, either version 3 of the License, or | ||
+ | * any later version. | ||
+ | * | ||
+ | * tcpserver is distributed in the hope that it will be useful, | ||
+ | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
+ | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
+ | * GNU General Public License for more details. | ||
+ | * | ||
+ | * You should have received a copy of the GNU General Public License | ||
+ | * along with tcpserver. If not, see <http://www.gnu.org/licenses/>. | ||
+ | */ | ||
+ | |||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <unistd.h> | ||
+ | #include <errno.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | #include <sys/types.h> | ||
+ | #include <sys/socket.h> | ||
+ | |||
+ | #include <arpa/inet.h> | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | printf("starting TCP Server\n"); | ||
+ | |||
+ | int server = socket(AF_INET, SOCK_STREAM, 0); | ||
+ | if(server < 0) { | ||
+ | perror("socket() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | | ||
+ | struct sockaddr_in local_addr; | ||
+ | memset((char *) &local_addr, 0, sizeof(local_addr)); | ||
+ | local_addr.sin_family = AF_INET; | ||
+ | local_addr.sin_port = htons(1234); | ||
+ | local_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
+ | |||
+ | if(bind(server, (struct sockaddr *)&local_addr, sizeof(local_addr))==-1) { | ||
+ | perror("bind() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | if(listen(server, 5)==-1) { | ||
+ | perror("listen() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | |||
+ | fd_set readfds, tmpfds; | ||
+ | FD_ZERO(&readfds); | ||
+ | FD_SET(server, &readfds); | ||
+ | int max_fd = server; | ||
+ | uint8_t buffer[1500]; | ||
+ | struct sockaddr_in remote_addr; | ||
+ | int alen, len; | ||
+ | for (;;) { | ||
+ | memcpy(&tmpfds, &readfds, sizeof(tmpfds)); | ||
+ | int num = select(max_fd+1, &tmpfds, NULL, NULL, NULL); | ||
+ | if(num == -1 && errno != EINTR) { | ||
+ | perror("select() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | if(num == -1 || !num) | ||
+ | continue; | ||
+ | |||
+ | if(FD_ISSET(server, &tmpfds)) { | ||
+ | int new_client = accept(server, (struct sockaddr *)&remote_addr, &alen); | ||
+ | if(new_client==-1) { | ||
+ | perror("accept() call failed"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | printf("new connection %s:%d (fd=%d)\n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port), new_client); | ||
+ | FD_SET(new_client, &readfds); | ||
+ | max_fd = (max_fd < new_client) ? new_client : max_fd; | ||
+ | FD_CLR(server, &tmpfds); | ||
+ | } | ||
+ | |||
+ | int fd; | ||
+ | for(fd=0; fd<=max_fd; ++fd) { | ||
+ | if(FD_ISSET(fd, &tmpfds)) { | ||
+ | len = recv(fd, buffer, 1500, 0); | ||
+ | if(len <= 0) { | ||
+ | if(len < 0) perror("recv() call failed"); | ||
+ | else fprintf(stderr, "client closed connection\n"); | ||
+ | | ||
+ | printf("removing client (fd=%d)\n", fd); | ||
+ | FD_CLR(fd, &readfds); | ||
+ | close(fd); | ||
+ | } | ||
+ | else | ||
+ | printf("Received %d Bytes from client (fd=%d)\n", len, fd); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | close(server); | ||
+ | | ||
+ | printf("exiting TCP Server\n"); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </file> | ||
+ | |||
---- | ---- | ||
{{tag>workshop}} | {{tag>workshop}} | ||
realraum Graz, Brockmanngasse 15, 8010 Graz, realraum - Verein für Technik in Kultur und Gesellschaft