C Prog - 保持网络服务器不断监听
我正在尝试使用在线教程学习winsock 编程。此示例来自 MSDN 库,但经过修改。我已经编译了它,它似乎只适用于一个请求。处理完单个请求后,服务器退出。我读过可以通过线程处理多个请求并使服务器持久化,但不知道如何做到这一点,并且在互联网上找不到有用的示例。请帮忙。
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 4096
#define DEFAULT_PORT "27015"
char recvbuf[DEFAULT_BUFLEN];
void handleBuffer()
{
recvbuf[DEFAULT_BUFLEN-1]='\0';
printf("\n************The server has received the following request***************\n");
printf("%s",recvbuf);
}
int __cdecl main(void)
{
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET,
ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,hints;
char* sendbuf = "HTTP/1.0 200 OK\r\nServer: Test\r\nContent-Type: text/HTML\r\n\r\n<html><title>Test Server</title><body><span style=\"color:#2032DC; font-family:arial; font-size:large; position:absolute; left:4%;\">This is test server responding.</span></body></html>";
int iResult, iSendResult;
int recvbuflen = DEFAULT_BUFLEN;
char e;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
else
printf("\nInitialising winsock...done");
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
printf("\n");
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
else
printf("\nResolving server address...done");
//localhost:27015/
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
else
printf("\nCreating connection socket...done");
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
else
printf("\nCreating listening socket...done");
printf("\nWaiting for connection... ");
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket);
iResult = recv(ClientSocket, recvbuf, recvbuflen,0);
if (iResult > 0)
{
printf("Bytes received: %d\n", iResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
iSendResult = send(ClientSocket,sendbuf,(int)strlen(sendbuf), 0 );
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
handleBuffer();
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
printf("\n\nPress any key to quit.");
getch();
return 0;
}
I am trying to learn winsock programming using online tutorials. This example is from the MSDN library, although modified. I have compiled it and it seems to be working fine for only one request. After handling a single request the server exits. I have read handling multiple request and making the server persistent can be done through threads, but have no idea how do so and no helpful examples found over the internet. Please help.
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 4096
#define DEFAULT_PORT "27015"
char recvbuf[DEFAULT_BUFLEN];
void handleBuffer()
{
recvbuf[DEFAULT_BUFLEN-1]='\0';
printf("\n************The server has received the following request***************\n");
printf("%s",recvbuf);
}
int __cdecl main(void)
{
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET,
ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,hints;
char* sendbuf = "HTTP/1.0 200 OK\r\nServer: Test\r\nContent-Type: text/HTML\r\n\r\n<html><title>Test Server</title><body><span style=\"color:#2032DC; font-family:arial; font-size:large; position:absolute; left:4%;\">This is test server responding.</span></body></html>";
int iResult, iSendResult;
int recvbuflen = DEFAULT_BUFLEN;
char e;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
else
printf("\nInitialising winsock...done");
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
printf("\n");
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
else
printf("\nResolving server address...done");
//localhost:27015/
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
else
printf("\nCreating connection socket...done");
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
else
printf("\nCreating listening socket...done");
printf("\nWaiting for connection... ");
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket);
iResult = recv(ClientSocket, recvbuf, recvbuflen,0);
if (iResult > 0)
{
printf("Bytes received: %d\n", iResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
iSendResult = send(ClientSocket,sendbuf,(int)strlen(sendbuf), 0 );
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
handleBuffer();
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
printf("\n\nPress any key to quit.");
getch();
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
很简单。
这将返回用于与连接的客户端通信的套接字,您所要做的就是为此套接字执行读/写循环并将其粘贴到新线程中。
同时,保持主循环在accept()上。
什么是你不明白的?
编辑
假设您要使用 Posix Threads,请看一下这个
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
掌握这个之后您可能需要更多的功能和灵活性:请查看http://www.lowtek.com/sockets/ select.html
您可以使用 select 来避免使用线程,您可以使用它通过线程分配您的客户端(例如 1..N 个客户端由 1 个线程管理)
备注
等等你的代码中有一个漏洞:
然后你在接收中使用它..这很糟糕,这可能会产生溢出,为了解决这个问题,请将你的缓冲区声明为:
字符recvbuf[DEFAULT_BUFLEN + 1];
It's straight forward.
This returns the socket used to communicate with the connected client, all you have to do is do a read/write loop for this socket and stick it into a new Thread.
Meanwhile, keep your main looping on the accept().
What's you don't get?
EDIT
Assuming you're going to use Posix Threads, have a look at this
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
After mastering this, you might need more power and flexibility: check this out http://www.lowtek.com/sockets/select.html
You can use select to avoid using threads, you can use it to distribute your clients through threads (like 1..N client is/are managed by 1 thread)
Remark
Wait there's a hole in your code:
then you use this into the receive.. it's bad, this might produce an overflow, in order to solve this, declare your buffer as:
char recvbuf[DEFAULT_BUFLEN + 1];