创建解决方案,添加ws2_32.lib就不说了,详情参考WinSocket编程(C++)实例一
话不多说,直接上代码:
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "winsock2.h"
#define BUF_SIZE 1024
void ErrorHandling(char *message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hServSock,hClntSock;
char message[BUF_SIZE];
int strLen,i;
SOCKADDR_IN servAdr,clntAdr;
int clntAdrSize;
if(argc!=2)
{
printf("Usage:%s\n",argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
ErrorHandling("WSAStartup() error!");
hServSock=socket(PF_INET,SOCK_STREAM,0);
if(hServSock==INVALID_SOCKET)
ErrorHandling("socket() error!");
memset (&servAdr,0,sizeof(servAdr));
servAdr.sin_family=AF_INET;
servAdr.sin_addr.s_addr=htonl(INADDR_ANY);
servAdr.sin_port=htons(atoi(argv[1]));
if (bind(hServSock,(SOCKADDR*)&servAdr,sizeof(servAdr))==SOCKET_ERROR)
ErrorHandling("bind() error!");
if (listen(hServSock,5)==SOCKET_ERROR)
ErrorHandling("listin() error");
clntAdrSize=sizeof(clntAdr);
for(i=0;i<5;i++)
{
hClntSock=accept(hServSock,(SOCKADDR*)&clntAdr,&clntAdrSize);
if(hClntSock==-1)
ErrorHandling("accept() error");
else
printf("Connected client %d \n",i+1);
while((strLen=recv(hClntSock,message,BUF_SIZE,0))!=0)
send(hClntSock,message,strLen,0);
closesocket(hClntSock);
}
closesocket(hServSock);
WSACleanup();
return 0;
}
void ErrorHandling(char* message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "winsock2.h"
#define BUF_SIZE 1024
void ErrorHandling(char* message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
char message[BUF_SIZE];
int strLen;
SOCKADDR_IN servAdr;
if(argc!=3)
{
printf("Usage:%s \n",argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
ErrorHandling("WSAStartup() error!");
hSocket=socket(PF_INET,SOCK_STREAM,0);
if(hSocket==INVALID_SOCKET)
ErrorHandling("socket() error");
memset(&servAdr,0,sizeof(servAdr));
servAdr.sin_family=AF_INET;
servAdr.sin_addr.s_addr=inet_addr(argv[1]);
servAdr.sin_port=htons(atoi(argv[2]));
if (connect(hSocket,(SOCKADDR*)&servAdr,sizeof(servAdr))==SOCKET_ERROR)
ErrorHandling("connect() error!");
else
puts("Connected........");
while(1)
{
fputs("Input message (Q to quit):",stdout);
fgets(message,BUF_SIZE,stdin);
if(!strcmp(message,"q\n")||!strcmp(message,"Q\n"))
break;
send(hSocket,message,strlen(message),0);
strLen=recv(hSocket,message,BUF_SIZE-1,0);
message[strLen]=0;
printf("Message from server:%s",message);
}
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char* message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
回声客户端存在的问题
下列是echo_ client.cpp的代码。
send(hSocket,message,strlen(message),0);
strLen=recv(hSocket,message,BUF_SIZE-1,0);
message[strLen]=0;
printf("Message from server:%s",message);
以上代码有个错误假设:
“每次调用recv、send函数时都会以字符串为单位执行实际的I/O操作。’
当然,每次调用send函数都会传递1个字符串,因此这种假设在某种程度上也算合理。但大
家还记得“TCP不存在数据边界”吗?上述客户端是基于TCP的,因此,多次调用send函数传递的字符串有可能一次性传递到服务器端。此时客户端有可能从服务器端收到多个字
符串,这不是我们希望看到的结果。还需考虑服务器端的如下情况:
“字符串太长,需要分2个数据包发送!”
服务器端希望通过调用1次write函数传输数据,但如果数据太大,操作系统就有可能把数据
分成多个数据包发送到客户端。另外,在此过程中,客户端有可能在尚未收到全部数据包时就调用read函数。
所有这些问题都源自TCP的数据传输特性。那该如何解决呢?请继续阅读下文
“但上述示例不是正常运转了吗?”
当然,我们的回声服务器端/客户端给出的结果是正确的。但这只是运气好罢了!只是因为
收发的数据小,而且运行环境为同一台计算机或相邻的两台计算机,所以没发生错误,可实际上仍存在发生错误的可能。
回声服务器端没有问题,只有回声客户端有问题?
问题不在服务器端,而在客户端。但只看代码也许不太好理解,因为I/O中使用了相同的函
数。先回顾一下回声服务器端的I/O相关代码,下面是echo_ server.cpp中的代码。
while((str_ len = read(c1nt_ sock, message, BUF_ SIZE)) != e)
write(c1nt_ sock, message, str_ _len);
接着回顾回声客户端代码,下面是echo cient.cpp中的代码。
write(sock, message, strlen(message));
str_ len = read(sock, message, BUF_ SIZE - 1);
二者都在循环调用read或write函数。实际上之前的回声客户端将0接收自己传输的数据,
不过接收数据时的单位有些问题。扩展客户端代码回颐范围,下面是echo_client.cpp中的代码。
while(1)
{
fputs("Input message (Q to quit):",stdout);
fgets(message,BUF_SIZE,stdin);
if(!strcmp(message,"q\n")||!strcmp(message,"Q\n"))
break;
send(hSocket,message,strlen(message),0);
strLen=recv(hSocket,message,BUF_SIZE-1,0);
message[strLen]=0;
printf("Message from server:%s",message);
}
大家现在理解了吧?回声客户端传输的是字符串,而且是通过调用write函数-次性发送的。
之后还调用一次read函数,期待着接收自己传输的字符串。这就是问题所在。
“既然回声客户端会收到所有字符串数据,是否只需多等一会儿?过一段时间后再
调用read函数是否可以一次性读取所有字符串数据?”
的确,过一段时间后即可接收,但需要等多久?要等10分钟吗?这不符合常理,理想的客户
端应在收到字符串数据时立即读取并输出。
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "winsock2.h"
//#include "unistd.h"
//#include "arpa/inet.h"
//#include "sys/socket.h"
#define BUF_SIZE 1024
void ErrorHandling(char* message);
int main(int argc, char* argv[])
{
int sock;
WSADATA wsaData;
int write,read,close;
char message[BUF_SIZE];
int str_len,recv_len,recv_cnt;
struct sockaddr_in serv_adr;
if(argc!=3)
{
printf("Usage:%s \n",argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
ErrorHandling("WSAStartup() error!");
sock=socket(PF_INET,SOCK_STREAM,0);
if(sock==-1)
ErrorHandling("socket() error");
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
if (connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr))==-1)
ErrorHandling("connect() error!");
else
puts("Connected........");
while(1)
{
fputs("Input message (Q to quit):",stdout);
fgets(message,BUF_SIZE,stdin);
if(!strcmp(message,"q\n")||!strcmp(message,"Q\n"))
break;
str_len=send(sock,message,strlen(message),0);
recv_len=0;
while (recv_len
虽然服务器可以接收两个客户端的请求,但是只能一个一个服务,暂时还不能实现同时接受请求。