LINUX.ORG.RU

Сокеты

 , , ,


0

1

Здравствуйте! Помогите, пожалуйста со следующей проблемой. У меня есть готовый код, описывающий взаимодействие клиент-сервер. Но он работает как общий чат.То есть при отправке сообщения на сервер это сообщение видят все клиенты. Этот код нужно доработать, так чтобы клиент мог выбирать адресата из списка всех клиентов и общаться только с ним. Можете подсказать как это организовать? Или какие ошибки исправить в коде?

Код сервера:

include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <strings.h>

#include <poll.h>
#define IPADDRESS "127.0.0.1"
#define PORT 6666
#define MAXLINE 1024
#define LISTENQ 5
#define OPEN_MAX 1000
#define INFTIM -1

int bind_and_listen()
{
	int serverfd;
	struct sockaddr_in my_addr;
	unsigned int sin_size;
	if((serverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf ("error socket");
		return -1;
	}
	printf("socket ok\n");
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(PORT);
	my_addr.sin_addr.s_addr = INADDR_ANY;
	bzero(&(my_addr.sin_zero), 0);
	if(bind(serverfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1)
	{
		printf("error bind");
		return -2;
	}
	printf("bind ok\n");
	if(listen(serverfd, LISTENQ) == -1)
	{
		printf("error listen");
		return -3;
	}
	printf("listen ok\n");
	return serverfd;
}

void do_poll(int listenfd)
{
	int connfd, sockfd;
	struct sockaddr_in cliaddr;
	socklen_t cliaddrlen;
	struct pollfd clientfds[OPEN_MAX];      
	int maxi;
	int sin_port2[5];
	int i,j;
	int nready;
	clientfds[0].fd = listenfd;
	clientfds[0].events = POLLIN;
	for(i = 1; i<OPEN_MAX; i++)
		clientfds[i].fd = -1;
	maxi = 0;

	while(1)
	{
		nready = poll(clientfds, maxi+1, INFTIM);
		if(nready == -1)
		{
			printf("poll error");
			exit(1);
		}
		if(clientfds[0].revents & POLLIN)
		{
			cliaddrlen = sizeof(cliaddr);
			if((connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen)) <0)
			{
				
					printf("accept error");
					exit(1);
				
			}
			fprintf(stdout, "accept a new client:%s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
			for(i = 1; i<OPEN_MAX; i++)
			{
				if(clientfds[i].fd<0)
				{
					clientfds[i].fd = connfd;
					break;
				}
			}
			if(i == OPEN_MAX)
			{
				fprintf(stderr, "too many clients.\n");
				exit(1);
			}
			sin_port2[i]=cliaddr.sin_port;
			clientfds[i].events = POLLIN;
			maxi = (i>maxi?i:maxi);
			if(--nready<=0)  
				continue;
		}
		
		char buf[MAXLINE];
                char BUF[80];
		
		memset(buf, 0, MAXLINE);
		int readlen = 0;
		for(i = 1; i<maxi; i++)    
		{
			if(clientfds[i].fd<0) continue;
				
			if(clientfds[i].revents & POLLIN)
			{
				readlen = read(clientfds[i].fd, buf, MAXLINE);
				if(readlen == 0)
				{
					close(clientfds[i].fd);
					clientfds[i].fd = -1;
					continue;
				}
				printf("msg is:");
				
				memset(BUF,0,sizeof(BUF));
				sprintf(BUF,"%d :%s",sin_port2[i],buf);
				printf("%s",BUF);
				
                                for(j=1;j<maxi;j++)
				{
				if(i!=j){
				write(clientfds[j].fd, BUF, sizeof(BUF));
				}
				}
	                                
			}
		}
	}
}
int main(int argc, char* argv[])
{
	int listenfd = bind_and_listen();
	if(listenfd<0)
	{
		return 0;
	}
	do_poll(listenfd);
	return 0;
}

Код клиента:


#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<poll.h>
#define IPADDRESS "127.0.0.1"
#define PORT 20113
#define MAXLINE 1024
#define max(a, b) (a>b)?a:b
static void handle_connection(int sockfd);
int main(int argc, char* argv[])
{
	int connfd = 0;
	int clen = 0;
	struct sockaddr_in client;
	if(argc<2)
	{
		printf("Usage: clientent[server IP address]\n");
		return -1;
	}
	client.sin_family = AF_INET;
	client.sin_port = htons(PORT);
	client.sin_addr.s_addr = inet_addr(argv[1]);
	connfd = socket(AF_INET, SOCK_STREAM, 0);
	if(connfd<0)
	{
		printf("error socket");
		return -1;
	}
	if(connect(connfd, (struct sockaddr*)&client, sizeof(client))<0)
	{
		printf("error connect");
		return -1;
	}
	handle_connection(connfd);
	return 0;
}

static void handle_connection(int sockfd)
{
	char sendline[MAXLINE], recvline[MAXLINE];
	int maxfdp, stdineof;
	struct pollfd pfds[2];
	int n;
	pfds[0].fd = sockfd;
	pfds[0].events = POLLIN;
	pfds[1].fd = STDIN_FILENO;
	pfds[1].events = POLLIN;
	while(1)
	{
		poll(pfds, 2, -1);
		if(pfds[0].revents & POLLIN)
		{
			n = read(sockfd, recvline, MAXLINE);
			if(n == 0)
			{
				fprintf(stderr, "client: server is closed.\n");
				close(sockfd);
			}
			write(STDOUT_FILENO, recvline, n);
		}
		if(pfds[1].revents & POLLIN)
		{
			n = read(STDIN_FILENO, sendline, MAXLINE);
			if(n == 0)
			{
				shutdown(sockfd, SHUT_WR);
				continue;
			}
			write(sockfd, sendline, n);
		}
	}
}

[code = C]

для начала можно начать с такого примитива

создайте файл с полями - username, password. из этого файла сервер при запуске считает базу пользователей для авторизации. При подключении клиента к серверу, сервер по этой базе авторизует пользователя - отправит клиенту приглашение - спросит имя и пароль у пользователя выдав username: и password: соответственно. После успешной авторизации пользователя на сервере каждому имени пользователя сопоставите id сокета клиента (или по какому id у вас размечены соединения с клиентами) с которого авторизовался пользователь. т.е. будет создана связь - username - clientSocketId.

Так же нужно на сервере реализовать протокол для выбора пользователем с кем делать чат.

Условимся - строки с командами начинаются с символа #.

Клиент (он же теперь авторизованный пользователь) прислал серверу #show users, сервер по символу # определил что клиент прислал команду и сервер ее детектировал (сравнил со списком встроенных команд), далее сервер по базе авторизованных пользователей сформировал список (за исключением пользователя который прислал эту команду) и отправил его клиенту.

затем клиент прислал команду #chat +username (username - имя авторизованного пользователя, ‘+’ добавить в чат, ‘-’ удалить из чата), сервер получив команду, детектировал ее, проверил есть ли такой username в базе авторизованных пользоватeлей, если есть отправил клиенту ответ - ОК (что означает чат с пользователем создан, или пользователь добавлен в чат или вообще что команда выполнена успешно). И настроил у себя чат-фильтр для пользователя , который отправил команду chat, в котором задал желаемого или несколько желаемых для общения пользователей.

После пользователь набирает в консоли сообщения и отправляет на сервер.

Все строки которые сервер получил не начинающиеся с # - есть сообщения.

После получения сообщения сервер проверяет настройки фильтра, если в фильтре есть пользователи-получатели, то отправляет сообщение согласно списку фильтра. Если фильтр пустой то отправляет уведомление-подсказку пользователю «Пользователи - для чата не заданы. Задайте пользователя командой #chat +username» + список авторизованных пользователей.

При получении пользователем сообщения, сервер добавляет перед сообщением имя пользователя от которого сообщение пришло.

Можно реализовать команду #show chatusers, которая выведет список пользователей в чате.

Тут можно придумывать и придумывать.

Vlad-76 ★★★ ()
Последнее исправление: Vlad-76 (всего исправлений: 13)