- //Server.cpp
- #include <stdio.h>
- #include <winsock2.h> //winsock.h (2种套接字版本)
- #pragma comment(lib,"ws2_32.lib") //wsock32.lib
- #define MAXSIZE 100 //
- int main()
- {
- //
- int retVal;
- char buf[MAXSIZE];
- //初始化套接字库
- WORD wVersionRequest;
- WSADATA wsadata;
- wVersionRequest=MAKEWORD(2,2);
- retVal=WSAStartup(wVersionRequest,&wsadata);
- if(retVal == SOCKET_ERROR)
- {
- printf("WSAStartup failed!");
- return -1;
- }
- //创建套接字
- SOCKET sServer;
- sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(sServer == INVALID_SOCKET)
- {
- printf("socket failed!");
- WSACleanup();
- return -1; //每次检测到失败后,即需要返回
- }
- //设置为非阻塞模式
- int imode=1;
- retVal=ioctlsocket(sServer,FIONBIO,(u_long *)&imode);
- if(retVal == SOCKET_ERROR)
- {
- printf("ioctlsocket failed!");
- closesocket(sServer);
- WSACleanup();
- return -1;
- }
- //绑定套接字并将其设置为监听状态
- SOCKADDR_IN addrServ;
- addrServ.sin_family=AF_INET;
- addrServ.sin_port =htons(5000);
- addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102");
- retVal=bind(sServer,(SOCKADDR *)&addrServ,sizeof(addrServ)); //绑定套接字到某一个具体的服务器
- if(retVal == SOCKET_ERROR)
- {
- printf("bind failed!");
- closesocket(sServer);
- WSACleanup();
- return -1;
- }
- retVal=listen(sServer,1); //第二个参数,表示最大连接数目
- if(retVal == SOCKET_ERROR)
- {
- printf("listen failed!");
- closesocket(sServer);
- WSACleanup();
- return -1;
- }
- //接受连接
- sockaddr_in addrClient; //定义一个临时地址,用于接受连接(注意:某个客户端由Client.cpp确定)
- int len=sizeof(sockaddr_in);
- SOCKET sClient;
- int errcode;
- while(true)
- {
- sClient=accept(sServer,(sockaddr *)&addrClient,&len);
- if(sClient == INVALID_SOCKET)
- {
- errcode=WSAGetLastError();
- if(errcode == WSAEWOULDBLOCK) //表示没有客户端发起连接,继续循环
- {
- Sleep(100);
- continue;
- }
- else
- {
- printf("accept failed!");
- closesocket(sServer); //连接失败,关闭服务器套接字并释放套接字库
- WSACleanup(); //
- return -1;
- }
- }
- break; //
- }
- //接收数据
- while(true)
- {
- retVal=recv(sClient,buf,strlen(buf),0);
- if(retVal == SOCKET_ERROR)
- {
- errcode=WSAGetLastError(); //这个变量errcode没有重复定义吗?
- if(errcode == WSAEWOULDBLOCK) //
- {
- Sleep(100);
- continue;
- }
- else
- {
- if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN)
- {
- closesocket(sClient);
- closesocket(sServer);
- WSACleanup();
- return -1;
- }
- }
- }
- if(buf == "quit") //如果接收数据为"quit",则发送回显"quit"
- {
- retVal=send(sClient,buf,strlen(buf),0);
- break;
- }
- else
- {
- //发送数据
- while(true)
- {
- retVal=send(sClient,buf,strlen(buf),0); //a.回显接收数据;b.第四个参数:0?
- if(retVal == SOCKET_ERROR) //错误处理
- {
- errcode=WSAGetLastError();
- if(errcode == WSAEWOULDBLOCK) //
- {
- Sleep(100);
- continue;
- }
- else
- {
- closesocket(sClient);
- closesocket(sServer);
- WSACleanup();
- return -1;
- }
- }
- break; //如果发送数据成功,则退出循环
- }
- }
- }
- }
- //Client.cpp
- #include <stdio.h>
- #include <WinSock2.h> //winsock.h
- #pragma comment(lib,"ws2_32.lib"); //wsock32.lib
- #include <iostream>
- using namespace std;
- #include <string.h> //strcpy函数
- #define MAXSIZE 100 //
- int main()
- {
- //
- int retVal;
- char buf[MAXSIZE];
- //初始化套接字库
- WORD wVersionRequest;
- WSADATA wsadata;
- wVersionRequest=MAKEWORD(2,2);
- retVal=WSAStartup(wVersionRequest,&wsadata);
- if(retVal == SOCKET_ERROR)
- {
- printf("WSAStartup failed!");
- return -1;
- }
- //创建套接字
- SOCKET sClient;
- sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(sClient == INVALID_SOCKET)
- {
- printf("socket failed!");
- WSACleanup();
- return -1; //每次检测到失败后,即需要返回
- }
- //设置为非阻塞模式
- int imode=1;
- retVal=ioctlsocket(sClient,FIONBIO,(u_long *)&imode);
- if(retVal == SOCKET_ERROR)
- {
- printf("ioctlsocket failed!");
- closesocket(sClient);
- WSACleanup();
- return -1;
- }
- //发起连接
- sockaddr_in addrServ;
- addrServ.sin_family=AF_INET; //表示使用的是,TCP/IP地址家族
- addrServ.sin_port =htons(5000); //为什么要使用htons宏?
- addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102");
- int len=sizeof(sockaddr_in); //sizeof只是一个运算符,不是函数
- while(true)
- {
- retVal=connect(sClient,(sockaddr *)&addrServ,len); //连接到某一个具体的服务器
- if(retVal == INVALID_SOCKET)
- {
- int errcode=WSAGetLastError();
- if(errcode==WSAEWOULDBLOCK || errcode==WSAEINVAL) //表示服务器端未准备好,继续循环
- {
- Sleep(100);
- continue;
- }
- else
- {
- if(errcode == WSAEISCONN) //连接成功,则退出
- {
- break;
- }
- else //否则连接失败,关闭客户端套接字并释放套接字库
- {
- printf("connect failed!");
- closesocket(sClient);
- WSACleanup(); //
- return -1;
- }
- }
- }
- }
- //发送数据
- while(true)
- {
- //
- //scanf(buf);
- //cin>>buf;
- strcpy(buf,"Hello TCP!");
- retVal=send(sClient,buf,strlen(buf),0); //a.回显接收数据;b.第四个参数:0?
- if(retVal == SOCKET_ERROR) //错误处理
- {
- int errcode=WSAGetLastError();
- if(errcode == WSAEWOULDBLOCK) //
- {
- Sleep(100);
- continue;
- }
- else
- {
- printf("send failed!");
- closesocket(sClient);
- //closesocket(sServer);
- WSACleanup();
- return -1;
- }
- }
- break; //如果发送数据成功,则退出循环
- }
- //接收数据
- while(true)
- {
- retVal=recv(sClient,buf,strlen(buf),0);
- if(retVal == SOCKET_ERROR)
- {
- int errcode=WSAGetLastError(); //这个变量errcode没有重复定义吗?
- if(errcode == WSAEWOULDBLOCK) //
- {
- Sleep(100);
- continue;
- }
- else
- {
- if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN)
- {
- printf("recv failed!");
- closesocket(sClient);
- //closesocket(sServer);
- WSACleanup();
- return -1;
- }
- }
- }
- break;
- }
- }
1.
#include <winsock2.h> //winsock.h (2种套接字版本)
#pragma comment(lib,"ws2_32.lib") //wsock32.lib
2.
retVal=ioctlsocket(sServer,FIONBIO,(u_long *)&imode); //第3个参数通常设为1(同时第2个参数设为FIONBIO),表示非阻塞模式
3.
a. //绑定套接字并将其设置为监听状态
SOCKADDR_IN addrServ;
addrServ.sin_family=AF_INET;
addrServ.sin_port =htons(5000);
addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102");
retVal=bind(sServer,(SOCKADDR *)&addrServ,sizeof(addrServ)); //绑定套接字到某一个具体的服务器
这一段代码表明,bind函数需要定义一个addrServ,并且要为每个字段赋值。
b. retVal=listen(sServer,1); //第二个参数,表示最大连接数目
4.
//接受连接
sockaddr_in addrClient; //定义一个临时地址,用于接受连接(注意:某个客户端由Client.cpp确定)
int len=sizeof(sockaddr_in);
SOCKET sClient;
int errcode;
while(true)
{
sClient=accept(sServer,(sockaddr *)&addrClient,&len);
if(sClient == INVALID_SOCKET)
{
errcode=WSAGetLastError();
if(errcode == WSAEWOULDBLOCK) //表示没有客户端发起连接,继续循环
{
……
5.
retVal=recv(sClient,buf,strlen(buf),0);//第4个参数,表示影响该函数的行为(通常设为0)
retVal=send(sClient,buf,strlen(buf),0); //a.回显接收数据;b.第四个参数:0?
------------------------------------------------------------------------------------------------
1.
addrServ.sin_port =htons(5000); //为什么要使用htons宏?前者的字段类型和宏的返回值类型一致
addrServ.sin_addr.S_un.S_addr=inet_addr("192.168.0.102"); //同理,后者函数的返回值类型和字段类型一致
2.
//scanf(buf); //问题①:为何这两个发送字符串我发送不了?
//cin>>buf;
strcpy(buf,"Hello TCP!"); //发送固定字符串
3.
问题②:下次继续做实验,bind failed的原因,而且是Client.cpp端出现的 真奇怪?(自己有调试,结果发现port字段和自己设置的不一致,不知为何)