Создать собственный клиент быстрых сообщений (возможно, и сервер – зависит от выбранной архитектуры), который бы работали в рамках сети.
Как я понял, это что-то на подобии чата. Есть эхо-сервер. Хочу переделать его, возможно ли это? И как лучше сделать?
Эхо сервер такой: client.c
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <limits.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define PORT 1027
#define MAXLINE 256
#define SA struct sockaddr
/*
* Обработчик фатальных ошибок.
*/
void error(const char *s)
{
perror(s);
exit(-1);
}
/*
* Функции-обертки.
*/
int Socket(int domain, int type, int protocol)
{
int rc;
rc = socket(domain, type, protocol);
if(rc == -1) error("socket()");
return rc;
}
void Connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
{
int rc;
rc = connect(socket, addr, addrlen);
if(rc == -1) error("connect()");
}
void Close(int fd)
{
int rc;
for(;;) {
rc = close(fd);
if(!rc) break;
if(errno == EINTR) continue;
error("close()");
}
}
void Inet_aton(const char *str, struct in_addr *addr)
{
int rc;
rc = inet_aton(str, addr);
if(!rc) {
/* Функция inet_aton() не меняет errno в случае ошибки. Чтобы
сообщение, выводимое error(), было более осмысленным,
присваиваем errno значение EINVAL. */
errno = EINVAL;
error("inet_aton()");
}
}
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
{
int rc;
for(;;) {
rc = select(n, readfds, writefds, exceptfds, timeout);
if(rc != -1) break;
if(rc == EINTR) continue;
error("select()");
}
return rc;
}
size_t Read(int fd, void *buf, size_t count)
{
ssize_t rc;
for(;;) {
rc = read(fd, buf, count);
if(rc != -1) break;
if(errno == EINTR) continue;
error("read()");
}
return rc;
}
size_t Write(int fd, const void *buf, size_t count)
{
ssize_t rc;
for(;;) {
rc = write(fd, buf, count);
if(rc != -1) break;
if(errno == EINTR) continue;
error("write()");
}
return rc;
}
/*
* Запись count байтов в сокет.
*/
size_t writen(int socket, const char *buf, size_t count)
{
const char *p;
size_t n, rc;
/* Проверить корректность переданных аргументов. */
if(buf == NULL) {
errno = EFAULT;
error("writen()");
}
p = buf;
n = count;
while(n) {
rc = Write(socket, p, n);
n -= rc;
p += rc;
}
return count;
}
void show_usage()
{
puts("Usage: client ip_address");
exit(-1);
}
void do_work(int socket)
{
int n;
fd_set readfds;
char s[MAXLINE];
ssize_t rc;
n = MAX(STDIN_FILENO, socket) + 1;
for(;;) {
/* Инициализировать набор дескрипторов. */
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
FD_SET(socket, &readfds);
Select(n, &readfds, NULL, NULL, NULL);
if(FD_ISSET(STDIN_FILENO, &readfds)) {
rc = Read(STDIN_FILENO, s, MAXLINE);
if(!rc) break;
writen(socket, s, rc);
}
if(FD_ISSET(socket, &readfds)) {
rc = Read(socket, s, MAXLINE);
if(!rc) break;
Write(STDOUT_FILENO, s, rc);
}
}
}
int main(int argc, char **argv)
{
int socket;
struct sockaddr_in servaddr;
if(argc != 2) show_usage();
socket = Socket(PF_INET, SOCK_STREAM, 0);
/* Инициализировать структуру адреса сокета. */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
Inet_aton(argv[1], &servaddr.sin_addr);
Connect(socket, (SA *) &servaddr, sizeof(servaddr));
do_work(socket);
Close(socket);
return 0;
}
/*
* Конфигурация сервера.
*/
#define PORT 1027
#define BACKLOG 5
#define MAXLINE 256
#define SA struct sockaddr
/*
* Обработчик фатальных ошибок.
*/
void error(const char *s)
{
perror(s);
exit(-1);
}
/*
* Функции-обертки.
*/
int Socket(int domain, int type, int protocol)
{
int rc;
rc = socket(domain, type, protocol);
if(rc == -1) error("socket()");
return rc;
}
int Bind(int socket, struct sockaddr *addr, socklen_t addrlen)
{
int rc;
rc = bind(socket, addr, addrlen);
if(rc == -1) error("bind()");
return rc;
}
int Listen(int socket, int backlog)
{
int rc;
rc = listen(socket, backlog);
if(rc == -1) error("listen()");
return rc;
}
int Accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
{
int rc;
for(;;) {
rc = accept(socket, addr, addrlen);
if(rc != -1) break;
if(errno == EINTR || errno == ECONNABORTED) continue;
error("accept()");
}
return rc;
}
void Close(int fd)
{
int rc;
for(;;) {
rc = close(fd);
if(!rc) break;
if(errno == EINTR) continue;
error("close()");
}
}
size_t Read(int fd, void *buf, size_t count)
{
ssize_t rc;
for(;;) {
rc = read(fd, buf, count);
if(rc != -1) break;
if(errno == EINTR) continue;
error("read()");
}
return rc;
}
size_t Write(int fd, const void *buf, size_t count)
{
ssize_t rc;
for(;;) {
rc = write(fd, buf, count);
if(rc != -1) break;
if(errno == EINTR) continue;
error("write()");
}
return rc;
}
void *Malloc(size_t size)
{
void *rc;
rc = malloc(size);
if(rc == NULL) error("malloc()");
return rc;
}
void Pthread_create(pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
int rc;
rc = pthread_create(thread, attr, start_routine, arg);
if(rc) {
errno = rc;
error("pthread_create()");
}
}
/*
* Чтение строки из сокета.
*/
size_t reads(int socket, char *s, size_t size)
{
char *p;
size_t n, rc;
/* Проверить корректность переданных аргументов. */
if(s == NULL) {
errno = EFAULT;
error("reads()");
}
if(!size) return 0;
p = s;
size--;
n = 0;
while(n < size) {
rc = Read(socket, p, 1);
if(rc == 0) break;
if(*p == '\n') {
p++;
n++;
break;
}
p++;
n++;
}
*p = 0;
return n;
}
/*
* Запись count байтов в сокет.
*/
size_t writen(int socket, const char *buf, size_t count)
{
const char *p;
size_t n, rc;
/* Проверить корректность переданных аргументов. */
if(buf == NULL) {
errno = EFAULT;
error("writen()");
}
p = buf;
n = count;
while(n) {
rc = Write(socket, p, n);
n -= rc;
p += rc;
}
return count;
}
void *serve_client(void *arg)
{
int socket;
char s[MAXLINE];
ssize_t rc;
/* Перевести поток в отсоединенное (detached) состояние. */
pthread_detach(pthread_self());
socket = *((int *) arg);
free(arg);
while((rc = reads(socket, s, MAXLINE)) > 0) {
if(writen(socket, s, rc) == -1) break;
}
Close(socket);
return NULL;
}
int main(void)
{
int lsocket; /* Дескриптор прослушиваемого сокета. */
int csocket; /* Дескриптор присоединенного сокета. */
struct sockaddr_in servaddr;
int *arg;
pthread_t thread;
/* Создать сокет. */
lsocket = Socket(PF_INET, SOCK_STREAM, 0);
/* Инициализировать структуру адреса сокета сервера. */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* Связать сокет с локальным адресом протокола. */
Bind(lsocket, (SA *) &servaddr, sizeof(servaddr));
/* Преобразовать неприсоединенный сокет в пассивный. */
Listen(lsocket, BACKLOG);
for(;;) {
csocket = Accept(lsocket, NULL, 0);
arg = Malloc(sizeof(int));
*arg = csocket;
Pthread_create(&thread, NULL, serve_client, arg);
}
return 0;
}