TCP / IP简单问题 [英] TCP/IP Simple Problem

查看:59
本文介绍了TCP / IP简单问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我使用的是简单的TCP / IP应用程序,包括2个部分:

服务器:

Hi,
I am using simple TCP/IP applications that is include 2 parts:
Server:

#pragma comment(lib, "Ws2_32.lib")

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>

using namespace std;

// Ok at first I am going to do some WinSock standard stuff
// If you don`t understand it watch my other tutorials

SOCKADDR_IN addr;

SOCKET sListen;
SOCKET sConnect;
SOCKET* Connections;

int addrlen = sizeof(addr);
int ConCounter = 0;

struct Buffer
{
	int ID;
	char Message[256];
};

int ServerThread(int ID)
{
	Buffer sbuffer;

	char* Recv = new char[256];
	ZeroMemory(Recv, 256);

	// In Send we will copy the content of the struct
	// and after this we will send "Send" to the client
	char* Send = new char[sizeof(Buffer)];
	ZeroMemory(Send, sizeof(Buffer));

	for(;; Sleep(10))
	{
		// Same here!
		if(recv(Connections[ID], Recv, 256, NULL))
		{
			sbuffer.ID = ID;
			memcpy(sbuffer.Message, Recv, 256);
			memcpy(Send, &sbuffer, sizeof(Buffer));

			for(int a = 0; a != ConCounter; a++)
			{
				if(Connections[a] == Connections[ID])
				{

				}
				else
				{
					send(Connections[a], Send, sizeof(Buffer), NULL);
				}
			}
			ZeroMemory(Recv, 256);
		}
	}

	return 0;
}

int InitWinSock()
{
	int RetVal = 0;
	WSAData wsaData;
	WORD DllVersion = MAKEWORD(2,1);
	RetVal = WSAStartup(DllVersion, &wsaData);

	return RetVal;
}

int main()
{
	int RetVal = 0;
	RetVal = InitWinSock();
	if(RetVal != 0)
	{
		MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
		exit(1);
	}

	Connections = (SOCKET*)calloc(64, sizeof(SOCKET));

	sListen = socket(AF_INET, SOCK_STREAM, NULL);
	sConnect = socket(AF_INET, SOCK_STREAM, NULL);

	addr.sin_addr.s_addr = inet_addr("66.96.201.81");
	addr.sin_port        = htons(1234);
	addr.sin_family      = AF_INET;

	bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
	
	listen(sListen, 64);

	for(;; Sleep(50))
	{
		if(sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen))
		{
			Connections[ConCounter] = sConnect;

			char* ID = new char[64];
			ZeroMemory(ID, sizeof(ID));

			itoa(ConCounter, ID, 10);
			send(Connections[ConCounter], ID, sizeof(ID), NULL);

			ConCounter = ConCounter + 1;
			CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ServerThread, (LPVOID)(ConCounter - 1), NULL, NULL);
		}
	}

	return 0;
}





和客户:



And Clients:

#pragma comment(lib, "Ws2_32.lib")

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>

using namespace std;


SOCKADDR_IN addr;

SOCKET sConnect;

// For this we need to send two information at one time:
// 1. The main message
// 2. The ID

// To send more than one information I will use a struct
struct Buffer
{
	int ID;
	char Message[256];
};

int ClientThread()
{
	Buffer sbuffer;

	char buffer[sizeof(sbuffer)] = {0};

	for(;; Sleep(10))
	{
		// The server will send a struct to the client
		// containing message and ID
		// But send only accepts a char as buffer parameter
		// so here we need to recv a char buffer and then
		// we copy the content of this buffer to our struct
		if(recv(sConnect, buffer, sizeof(sbuffer), NULL))
		{
			memcpy(&sbuffer, buffer, sizeof(sbuffer));
			cout << "<Client " << sbuffer.ID << ":> " << sbuffer.Message <<endl;
		}
	}

	return 0;
}

int main()
{
	system("cls");

	int RetVal = 0;

	WSAData wsaData;
	WORD DllVersion = MAKEWORD(2,1);
	RetVal = WSAStartup(DllVersion, &wsaData);
	if(RetVal != 0)
	{
		MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
		exit(1);
	}

	sConnect = socket(AF_INET, SOCK_STREAM, NULL);

	addr.sin_addr.s_addr = inet_addr("66.96.201.81");
	addr.sin_port        = htons(1234);
	addr.sin_family      = AF_INET;

	cout << "Connect to Masterserver? [ENTER]" <<endl;
	getchar();
	RetVal = connect(sConnect, (SOCKADDR*)&addr, sizeof(addr));

	if(RetVal != 0)
	{
		MessageBoxA(NULL, "Could not connect to server", "Error", MB_OK | MB_ICONERROR);
		main();
	}
	else
	{
		int ID;
		char* cID = new char[64];
		ZeroMemory(cID, 64);

		recv(sConnect, cID, 64, NULL);
		ID = atoi(cID);

		cout << "Connected" <<endl;
		cout << "You are Client No: " << ID <<endl;

        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ClientThread, NULL, NULL, NULL);
		
		for(;; Sleep(10))
		{
			char* buffer = new char[256];
			ZeroMemory(buffer, 256);

			cin >> buffer;
			getchar();
			
			send(sConnect, buffer, 256, NULL);
		}
	}

	return 0;
}





应用程序运行良好。我这里只有一个问题。

例如在client1中我写你好吗?然后按下回车键,在client2中,它会写出完全你好吗?并在一行中解析它,并按字母逐字逐句写入:

如何







如何解决这个问题?

问候,



Applications work good. I have only one problem here.
When in client1 for example I write "How are you?" and press enter, in client2 instead it write exactly ""How are you?" and in one line, it parsing that and write in more lines word to word as below:
How
are
you
?
How I can fix this?
Regards,

推荐答案

TCP是面向字节流的协议,不是面向消息的。你假设你写了你好吗?作为消息,但TCP不会将此作为消息处理,相反,它将其作为一个字节序列处理,而另一方将接收它作为一个字节序列,可以在每两个字节之间断开。如果你想发送消息,那么你必须插入分隔符(例如字符流中的零字符和在接收器端,你必须在字节流入时将字节收集到缓冲区中,当你遇到分隔符时,你用整个收到的消息调用你的消息处理程序。



如果你这样写:



Messa ge10Message20



那么你可以逐字节地收到它,或者像这样:



混乱

a

ge

10M//此时你打电话给你的留言带有Message1的处理程序,你只留下缓冲区中的M作为下一条消息的开头。

essage2

0 //你打电话给你带有Message2的消息处理函数
TCP is a byte stream oriented protocol and NOT message oriented. You assume that you write "How are you?" as a message but TCP won't handle this as a message, instead it handles this as a byte sequence and the other side will receive this as a byte sequence that can be broken between every two bytes. If you want to send messages then you have to insert delimiters (for example zero characters into the byte stream and on the receiver side you have to collect bytes into a buffer as the bytes are flowing in and when you encounter a delimiter character you call your message handler with the whole received message.

If you write this:

"Message1" 0 "Message2" 0

Then you may receive it byte by byte or like this:

"Mess"
"a"
"ge"
"1" 0 "M" // at this point you call your message handler with "Message1" and you leave only the "M" in the buffer that is the beginning of the next message.
"essage2"
0 // you call your message handler function with "Message2"


不要为每个收到的消息发送换行符。您在 recv 调用中读取的数据可能不是从服务器发送的完整消息。
Don't send a newline with every received message. The data you read on a recv call may not be the complete message sent from the server.


这篇关于TCP / IP简单问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆