在windows操作系统中进行socket编程,服务器和客户端要各司其职,简单来说,
服务器端需要做的工作有:
1.创建套接字(socket函数)
2.锁定IP地址和端口(bind函数)
3.监听进入的链接(listen函数)
4.接受连接(accept函数)
5.收发数据(send/recv函数)
6.关闭连接(closesocket函数)
客户端需要的做的工作有:
1.创建套接字(socket函数)
2.连接到服务器端(connect函数)
3.收发数据(send/recv函数)
4.关闭连接(closesocket函数)
以下是一个简单的例子,代码是从网上找来的。但是感觉有些地方写的不够好,就稍微修改了一些地方,也勉强算原创吧。代码如下:
//Server.cpp
#include
#include
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#define PORT 4000
//#define IP_ADDRESS "127.0.0.1"
DWORD WINAPI ClientThread(LPVOID lpParameter)
{
SOCKET CientSocket = (SOCKET)lpParameter;
int Ret = 0;
char RecvBuffer[MAX_PATH];
while ( true )
{
memset(RecvBuffer, 0x00, sizeof(RecvBuffer));
Ret = recv(CientSocket, RecvBuffer, MAX_PATH, 0);
if ( Ret == 0 || Ret == SOCKET_ERROR )
{
cout<<"客户端退出!"<
}
cout<<"接收到客户信息为:"<
return 0;
}
int main(int argc, char* argv[])
{
WSADATA Ws;
SOCKET ServerSocket, CientSocket;
struct sockaddr_in LocalAddr, ClientAddr;
int Ret = 0;
int AddrLen = 0;
HANDLE hThread = NULL;
//Init Windows Socket
if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
{
cout<<"Init Windows Socket Failed::"<
}
//Create Socket
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( ServerSocket == INVALID_SOCKET )
{
cout<<"Create Socket Failed::"<
}
LocalAddr.sin_family = AF_INET;
// LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
LocalAddr.sin_addr.s_addr = INADDR_ANY;
// INADDR_ANY 表示下面的函数bind函数把刚才创建的socket绑定到当前的电脑的IP地址上。
LocalAddr.sin_port = htons(PORT);
memset(LocalAddr.sin_zero, 0x00, 8);
//Bind Socket
Ret = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
if ( Ret != 0 )
{
cout<<"Bind Socket Failed::"<
}
Ret = listen(ServerSocket, 10);
if ( Ret != 0 )
{
cout<<"listen Socket Failed::"<
}
cout<<"服务端已经启动"<
while ( true )
{
AddrLen = sizeof(ClientAddr);
CientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &AddrLen);
if ( CientSocket == INVALID_SOCKET )
{
cout<<"Accept Failed::"<
}
cout<<"客户端连接::"<
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)CientSocket, 0, NULL);
if ( hThread == NULL )
{
cout<<"Create Thread Failed!"<
}
CloseHandle(hThread);
}
closesocket(ServerSocket);
closesocket(CientSocket);
WSACleanup();
return 0;
}
以上是服务器端的代码,下面是客户端的代码:
//Client.cpp
#include
#include
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#define PORT 4000
//#define IP_ADDRESS "127.0.0.1"
int main(int argc, char* argv[])
{
WSADATA Ws;
SOCKET CientSocket;
struct sockaddr_in ServerAddr;
int Ret = 0;
int AddrLen = 0;
HANDLE hThread = NULL;
char SendBuffer[MAX_PATH];
// quick argument check
if(argc != 2)
{
fprintf(stderr, "usage: %s
ExitProcess(1);
}
//Init Windows Socket
if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
{
cout<<"Init Windows Socket Failed::"<
}
//Create Socket
CientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( CientSocket == INVALID_SOCKET )
{
cout<<"Create Socket Failed::"<
}
ServerAddr.sin_family = AF_INET;
// ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
ServerAddr.sin_addr.s_addr = inet_addr(argv[1]);//输入的IP地址作为服务器端IP去连接
ServerAddr.sin_port = htons(PORT);
memset(ServerAddr.sin_zero, 0x00, 8);
Ret = connect(CientSocket,(struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
if ( Ret == SOCKET_ERROR )
{
cout<<"Connect Error::"<
}
else
{
cout<<"连接成功!"<
while ( true )
{
cin.getline(SendBuffer, sizeof(SendBuffer));
Ret = send(CientSocket, SendBuffer, (int)strlen(SendBuffer), 0);
if ( Ret == SOCKET_ERROR )
{
cout<<"Send Info Error::"<
}
}
closesocket(CientSocket);
WSACleanup();
return 0;
}
这里面有几个地方需要注意一下:
1.这是windows控制台程序(console application)
2.Server.cpp中,有这样一行代码:
LocalAddr.sin_addr.s_addr = INADDR_ANY;
这样,在后面调用bind()函数的时候,程序就会把ServerSocket绑定在本电脑的IP地址上。当然,我们也可以指定一个固定的IP地址,就比如说程序中注释起来的两行代码:
#define IP_ADDRESS "127.0.0.1"
LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
不过,个人感觉用INADDR_ANY是最好的了,因为后者只能和客户端在同一台电脑上测试的时候才能正常运行,如果服务器端和客户端在不同的电脑上,后者就不行了。而前者即INADDR_ANY是一直行的。
3.Client.cpp中利用下面的代码进行参数的检查:
if(argc != 2)
{
fprintf(stderr, "usage: %s
ExitProcess(1);
}
假设客户端的可执行程序为clientSocket.exe,那么运行的时候应该遵循这样的格式:
clientSocket IP
这里的IP指的是服务器端的IP地址。
我使用VC6.0编译器编译了源代码,放在附件里面了。欢迎大家下载。
参考资料:http://www.cppblog.com/bujiwu/archive/2009/01/11/71707.aspx