Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 24.09.2012, 15:38   #1
Чиффа
Пользователь
 
Регистрация: 24.09.2012
Сообщений: 11
Печаль Клиент-сервер, потоки, загвоздка в постоянном чтении и отправке сообщений.

Здравствуйте уважаемые программисты, я пытаюсь написать программку для отправки и приёма сообщений(что-то вроде аськи), по средствам соединения сервер - клиент. Загвоздка в том чтобы и клиент и сервер могли одновременно и принимать и отправлять сообщения.
Если сможете напишите какую можно литературу почитать по программированию TCP и потоков, желательно чтобы доступным языком была написана)спасибо.
Заранее прошу прощения за быть может глупые ошибки в коде, я лишь начинающий программист) спасибо за понимание.
собственно код сервера:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <pthread.h>

using namespace std;

char Message1[300], Message2[300];
int sock;
int Client;

void * wrt(void * arg);
void * rd(void * arg);

int main( void )
{
char ClientName[30], PCName [30];

struct sockaddr_in serv; // Свойства(адрес) создаваемого сокета
gethostname(PCName, 30);


int r_bind;
int r_listen;
int r_read;
int r_write;

serv.sin_family = AF_INET;
serv.sin_port = htons( 7500 );
serv.sin_addr.s_addr = htonl( INADDR_ANY );
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( sock < 0 )
{
perror( "ошибка вызова socket" );
exit( 1 ) ;
}

r_bind = bind( sock, ( struct sockaddr * )&serv, sizeof( serv ) );
if ( r_bind < 0 )
{
perror( "ошибка вызова bind" );
exit( 1 );
}
//Ожидаем клиента
printf("Wait of client...\n");

r_listen = listen( sock, SOMAXCONN );
if ( r_listen )
{
perror( "ошибка вызова listen" );
exit (1);
}

Client = accept( sock, NULL , NULL );//( struct sockaddr * )&serv
if ( Client < 0 )
{
perror ( "ошибка вызова accept" );
exit( 1 );
}

r_read = recv( Client, ClientName, 30, 0 );
if ( r_read <= 0 )
{
perror( "ошибка вызова recv" );
exit( 1 );
}

r_write = send( Client, PCName , 31, 0 );
if ( r_write <= 0 )
{
perror( "ошибка вызова send" );
exit( 0 );
}
printf("Client ( \" %s \" ) has connected!\n", ClientName);

pthread_t thr1, thr2;
int id1 = 1;
int id2 = 2;
int result;

result = pthread_create(&thr1, NULL, wrt, &id1);
result = pthread_create(&thr2, NULL, rd, &id2);

result = pthread_join(thr1, NULL);
result = pthread_join(thr2, NULL);

// Закрытие сокетов и окончание работы
shutdown(sock, 0);
close(sock);
close(Client);
getchar();
return 0;
}

void * wrt(void * arg)
{
while(true)
{
scanf("%299s",Message1);
if (send(Client, Message1, 301, 0) != 'q')
printf("Sent!\n");
else printf("Error of sending!\n");
}
}
void * rd(void * arg)
{
while(true)
{
if (recv(Client, Message2, 300, 0) != 'q')
{
printf("\nreading:\t%s\n", Message2);
getchar();
}
else printf("Error of reading!\n");
}
}
и код клиента:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <pthread.h>

using namespace std;

char Message1[300],Message2[300];
int sock;
void * wrt(void * arg);
void * rd(void * arg);

int main( void )
{
char PCName[30], ServerName[30], IP[16] = { 0 };
struct sockaddr_in clien;
int r_connect;
int r_read;
int r_write;

//Ввод IP-адреса сервера
printf("Enter server's IP: ");
scanf("%15s", IP);

gethostname(PCName, 30); // Получение имени текущего ПК

clien.sin_family = AF_INET;
clien.sin_port = htons( 7500 );
clien.sin_addr.s_addr = inet_addr( IP );

sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( sock < 0 )
{
perror( "ошибка вызова socket" );
exit( 1 );
}

//Подключение к серверу
printf("connecting to server...\n");

r_connect = connect( sock, ( struct sockaddr *)&clien, sizeof( clien ) );
if ( r_connect )
{
perror( "ошибка вызова connect" );
exit( 1 );
}

r_write = send(sock, PCName, 31, 0 );
if ( r_write <= 0 )
{
perror( "ошибка вызова send" );
exit( 1 );
}

r_read = recv(sock, ServerName, 30, 0);
if ( r_read <= 0 )
perror( "ошибка вызова recv" );

printf("connect to \" %s \" \n", ServerName);

pthread_t thr1, thr2;
int id1 = 1;
int id2 = 2;
int result;

result = pthread_create(&thr1, NULL, wrt, &id1);
result = pthread_create(&thr2, NULL, rd, &id2);

result = pthread_join(thr1, NULL);
result = pthread_join(thr2, NULL);
// Закрытие сокетов и окончание работы с WinSock
shutdown(sock, 0);
close(sock);
getchar();
return 0;
}

void * wrt(void * arg)
{
while(true)
{
scanf("%299s",Message1);
if (send(sock, Message1, 301, 0) != 'q')
printf("Sent!\n");
else printf("Error of sending!\n");
}

}
void * rd(void * arg)
{
while(true)
{
if (recv(sock, Message2, 300, 0) != 'q')
{
printf("\nreading:\t%s\n", Message2);
getchar();
}
else printf("Error of reading!\n");
}
}
Чиффа вне форума Ответить с цитированием
Старый 25.09.2012, 15:24   #2
Tiva
Пользователь
 
Регистрация: 23.11.2011
Сообщений: 49
По умолчанию

во-первых, вместо инклюда всего по отдельности, половину из ваших инклюдов можно заменить одним
#include <windows.h> (в т.ч. винсокс)

во-вторых, вот пример моего клиент-сервер, сервер может держать соединения с больше чем одним клиентом
Код:
struct ClientServiceThread
{
	SOCKET listener;
	SOCKET * socket_client;
	struct sockaddr_in * address_client;
	int clientMaxCount;
	int clientCount;
};

struct ClientExchangeThread
{
	ClientServiceThread * cst;
	int clientIndex;
};

DWORD WINAPI ClientExchange(LPVOID data)
{
	ClientExchangeThread *cet = ((ClientExchangeThread*)data);
	ClientServiceThread *cst = cet->cst;
	int idx = cet->clientIndex;
	delete cet;
...
cst->clientCount--;
	closesocket(cst->socket_client[idx]);
	cst->socket_client[idx] = INVALID_SOCKET;
	return 0;
}

DWORD WINAPI ClientService(LPVOID data)
{
	ClientServiceThread *cst = ((ClientServiceThread*)data);
	while (true)
	{
		int i;
		for (i = 0; i < cst->clientMaxCount; i++)
			if (cst->socket_client[i] == INVALID_SOCKET)
				break;
		if (i < cst->clientMaxCount)
		{
			int sz = sizeof(sockaddr);
			cst->socket_client[i] = accept(cst->listener, (struct sockaddr *) cst->address_client + i, &sz);
			cst->clientCount++;
			ClientExchangeThread* cet = new ClientExchangeThread;
			cet->cst = cst;
			cet->clientIndex = i;
			DWORD cetThreadId;
			CreateThread(0, 0, &ClientExchange, cet, 0, &cetThreadId);
			Sleep(0);
		}
		else
			Sleep(500);
	}
}

#pragma argsused
int main(int argc, char* argv[])
{
	WSADATA version;
	DWORD startErr = WSAStartup(0x0202, &version);
	if (startErr)
	{
		cerr << "Windows socket library isn't version 2.2";
		return 1;
	}

	ClientServiceThread* cst = new ClientServiceThread;
	cst->listener = socket(AF_INET, SOCK_STREAM, 0);
	if (cst->listener == INVALID_SOCKET)
	{
		return 2;
	}

	struct sockaddr_in address_server;
	address_server.sin_family = AF_INET;
	address_server.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	address_server.sin_port = htons(1024);

	int bindErr = bind(cst->listener, (struct sockaddr *)&address_server, sizeof(address_server));
	if (bindErr < 0)
	{
		return 3;
	}

	cst->clientMaxCount = 2;
	cst->clientCount = 0;
	cst->socket_client = new SOCKET[cst->clientMaxCount];
	for (int i = 0; i < cst->clientMaxCount; i++)
		cst->socket_client[i] = INVALID_SOCKET;
	cst->address_client = new struct sockaddr_in[cst->clientMaxCount];
	listen(cst->listener, cst->clientMaxCount);

	DWORD cstThreadId;
	HANDLE cstThread = CreateThread(0, 0, &ClientService, cst, 0, &cstThreadId);
	Sleep(0);
...
        TerminateThread(cstThread, 1);
	for (int i = 0; i < cst->clientMaxCount; i++)
		if (cst->socket_client[i] != INVALID_SOCKET)
			closesocket(cst->socket_client[i]);
	delete [] cst->socket_client;
	delete [] cst->address_client;
	WSACleanup();
	delete cst;
	return 0;
}
Tiva вне форума Ответить с цитированием
Старый 25.09.2012, 15:27   #3
Tiva
Пользователь
 
Регистрация: 23.11.2011
Сообщений: 49
По умолчанию

а вот клиент
Код:
int main(int argc, char* argv[])
{
	WSADATA version;
	DWORD startErr = WSAStartup(0x0202, &version);
	if (startErr)
	{
		cerr << "Windows socket library isn't version 2.2";
		return 1;
	}

	SOCKET client;

	client = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in address_server;
	address_server.sin_family = AF_INET;
	address_server.sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK);
	address_server.sin_port = htons(1024);

	int connectErr;
	connectErr = connect(client, (struct sockaddr *) &address_server, sizeof(sockaddr));

	if (connectErr == SOCKET_ERROR)
	{
		return 2;
	}

	cout << "Connected" << endl;
...
closesocket(client);

	WSACleanup();
	return 0;
Tiva вне форума Ответить с цитированием
Старый 25.09.2012, 15:29   #4
Tiva
Пользователь
 
Регистрация: 23.11.2011
Сообщений: 49
По умолчанию

а по литературе
потоки:
http://www.realcoding.net/article/view/1749

сокеты(под виндос):
http://cs5856.userapi.com/u69125685/...4/WinSock1.pdf
Tiva вне форума Ответить с цитированием
Старый 25.09.2012, 15:41   #5
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,331
По умолчанию

Цитата:
Сообщение от Tiva Посмотреть сообщение
сервер может держать соединения с больше чем одним клиентом...
...в течении какогото времени, потом закончатся HANDLE-ы...
waleri вне форума Ответить с цитированием
Старый 25.09.2012, 15:57   #6
Чиффа
Пользователь
 
Регистрация: 24.09.2012
Сообщений: 11
По умолчанию

За ссылочки большое спасибо.

Цитата:
Сообщение от Tiva Посмотреть сообщение
во-первых, вместо инклюда всего по отдельности, половину из ваших инклюдов можно заменить одним
#include <windows.h> (в т.ч. винсокс)
[/CODE]
на счет windows.h - не получится, ибо сижу под линухом... и вот немного поправил ввод вывод, однако проблем только прибавилось, теперь клиент, если с сервера отправить сообщение выводит в постоянном цикле : "reading:", странно что при отправке на сервер всё ок....
Сервер:

pthread_t thr1, thr2;
int id1 = 1;
int id2 = 2;
int result;
result = pthread_create(&thr1, NULL, wrt, &id1);
result = pthread_create(&thr2, NULL, rd, &id2);

result = pthread_join(thr1, NULL);
result = pthread_join(thr2, NULL);

// Закрытие сокетов и окончание работы
shutdown(sock, 0);
close(sock);
close(Client);
getchar();
return 0;
}

void * wrt(void * arg)
{
while(true)
{
scanf("%299s",Message1);
if (send(Client, Message1, 301, 0) != EOF)
printf("Sent!\n");
else printf("Error of sending!\n");
int r_write = send(sock, Message1, 301, 0);
if ( r_write <= 0 )
{
perror( "ошибка вызова send" );
exit( 1 );
}
}
}

void * rd(void * arg)
{
while(true)
{
int i = recv(Client, Message2, 300, 0);
if ( i <= -1 )
{
printf("Error of reading!\n");
exit( 1 );
}
else printf("reading:\t%s\n", Message2);
}
}
Чиффа вне форума Ответить с цитированием
Старый 25.09.2012, 15:57   #7
Чиффа
Пользователь
 
Регистрация: 24.09.2012
Сообщений: 11
По умолчанию

И вот злощастный клиент:

pthread_t thr1, thr2;
int id1 = 1;
int id2 = 2;
int result;
result = pthread_create(&thr1, NULL, wrt, &id1);
result = pthread_create(&thr2, NULL, rd, &id2);

result = pthread_join(thr1, NULL);
result = pthread_join(thr2, NULL);

// Закрытие сокетов и окончание работы
shutdown(sock, 0);
close(sock);
getchar();
return 0;
}

void * wrt(void * arg)
{
while(true)
{
scanf("%299s",Message1);
if (send(sock, Message1, 301, 0) != EOF)
printf("Sent!\n");
else printf("Error of sending!\n");
int r_write = send(sock, Message1, 301, 0);
if ( r_write <= 0 )
{
perror( "ошибка вызова send" );
exit( 1 );
}
}
}

void * rd(void * arg)
{
while(true)
{
int i = recv(sock, Message2, 300, 0);
if ( i <= -1 )
{
printf("Error of reading!\n");
exit( 1 );
}
else printf("reading:\t%s\n", Message2);
}
}
//Целиком не выкладывал, кроме send и recv ничего не менял

Последний раз редактировалось Чиффа; 25.09.2012 в 16:04.
Чиффа вне форума Ответить с цитированием
Старый 25.09.2012, 16:03   #8
Чиффа
Пользователь
 
Регистрация: 24.09.2012
Сообщений: 11
По умолчанию

кстати так же не могу понять, при чтении сообщения сервер вначале выводит по 1 сообщению приходящему, а потом почему-то по 2 о_О...
на сколько я понял из манов команда recv ожидает прибытия сообщения из сокета, пока то не придёт... соответственно почему такая ерунда с прибытием сообщений на клиент, и почему по 2 сообщения печатает сервер, не понятно =(
Чиффа вне форума Ответить с цитированием
Старый 25.09.2012, 17:02   #9
Tiva
Пользователь
 
Регистрация: 23.11.2011
Сообщений: 49
По умолчанию

линукс не моё. даже не знаю чем помочь тогда твой код мне очень не понятен

я бы скинул весь код моего серверклиента, но раз линукс.. ну в общем надо?)
Tiva вне форума Ответить с цитированием
Старый 25.09.2012, 17:05   #10
Чиффа
Пользователь
 
Регистрация: 24.09.2012
Сообщений: 11
По умолчанию

Нет, спасибо, буду дальше разбираться... думаю рано или поздно дойдёт как сделать, а потом и как правильно сделать)
Чиффа вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как отправить видео захват(с веб-Кам.) Клиент->Сервер->Клиент RODNOC Мультимедиа в Delphi 17 03.10.2010 22:31
Ошибка при отправке сообщений через SMTPClient BoT_T Работа с сетью в Delphi 6 26.09.2010 17:16
Возможно-ли Клиент-серверное приложение типа Клиент(Pascal) а сервер(CGI)? Demol Работа с сетью в Delphi 1 21.04.2009 16:18
Формат передаваемых данных хабам локальной сети, при отправке личных сообщений из DC клиетов docm Общие вопросы .NET 0 18.11.2008 15:33