The socket interface has become ubiquitous in modern operating systems
- The socket programming interface under Windows is almost the same as in Linux
the difference
- The return type is different (handle type)
- The handle is not a file descriptor, and not all files are connected in Window (so send and recv cannot be used for sockets under Windows)
Usage of socket() under Windows
SOCKET s = {0};
s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // IPPROTO_TCP 明确指明创建 TCP 协议的套接字
if (s == INVALID) { // 创建套接字时出错,返回 INVALID_SOCKET
ERROR("...");
return -1;
}
Windows Network Programming Interface
#include <winsock2.h>
function prototype | Function description |
SOCKET socket(int af, int type, int protocal); | Create a socket in preparation for a network connection |
int connect(SOCKET s, const struct sockaddr *addr, int len); | Connect to a remote device at the specified address |
int send(SOCKET s, const char *buf, int len, int flags); | Send data to remote device |
int recv(SOCKET s char *buf, int len, int flags); | Receive data from remote devices |
int closesocket(SOCKET s); | close the connection, destroy the socket |
int bind(SOCKET s, const struct sockaddr *addr, int len); | Associate the socket with the specified address |
int listen(SOCKET s, int backlog); | Push socket into listening state, waiting for connection |
SOCKET accept(SOCKET s, struct sockaddr *addr, int len); | Receive client connections |
int shutdown(SOCKET s, int howto); | Close the connection, stop sending and receiving |
closes 与 shutdown(Linux 下也存在) 的区别:shoutdown 不释放 socket 资源
a few nuances
- Initialize the system environment through WSAStartup() (first call)
- socket(), accept() error returns INVALID_SOCKET (cannot default to -1)
- bind(), listen() error returns SOCKET_ERROR (cannot default to -1)
- connect(), send(), recv() error returns SOCKET_ERROR (cannot default to -1)
- Clean up the system environment via WSACleanup() (last call)
Special Instructions for Windows Network Programming
- Set the link ws2_32.lib in the project properties
- Define the variable WSADATA wd
Select socket version and initialize WSAStartup(MAKEWORD(2, 2), &wd)
Multiple socket versions exist in Windows
- MAKEWORD(1, 2) // major version is 1, minor version is 2, return 0x0201
- MAKEWORD(2, 2) // major version is 2, minor version is 2, returns 0x0202
Programming Lab: Windows Network Programming Examples
client.c
#include "stdafx.h"
#include <winsock2.h>
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET sock = 0; // 注意 socket 类型
struct sockaddr_in addr = {0};
int len = 0;
char buf[128] = {0};
char input[32] = {0};
int r = 0;
WSADATA wd = {0}; // 注意变量定义
if( WSAStartup(MAKEWORD(2, 2), &wd) != 0 ) // 注意初始化系统环境
{
printf("startup error\n");
return -1;
}
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if( sock == INVALID_SOCKET ) // 注意返回值类型
{
printf("socket error\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8888);
if( connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR ) // 注意返回值类型
{
printf("connect error\n");
return -1;
}
printf("connect success\n");
while( 1 )
{
printf("Input: ");
scanf("%s", input);
len = send(sock, input, strlen(input) + 1, 0);
r = recv(sock, buf, sizeof(buf), 0);
if( r > 0 )
{
printf("Receive: %s\n", buf);
}
else
{
break;
}
}
closesocket(sock); // 注意
WSACleanup(); // 注意清除系统环境
return 0;
}
server.c
// Server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET server = 0;
struct sockaddr_in saddr = {0};
SOCKET client = 0;
struct sockaddr_in caddr = {0};
int asize = 0;
int len = 0;
char buf[32] = {0};
int r = 0;
WSADATA wd = {0};
if( WSAStartup(MAKEWORD(2, 2), &wd) != 0 )
{
printf("startup error\n");
return -1;
}
server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if( server == INVALID_SOCKET )
{
printf("server socket error\n");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR )
{
printf("server bind error\n");
return -1;
}
if( listen(server, 1) == SOCKET_ERROR )
{
printf("server bind error\n");
return -1;
}
printf("server start success\n");
while( 1 )
{
asize = sizeof(caddr);
client = accept(server, (struct sockaddr*)&caddr, &asize);
if( client == INVALID_SOCKET )
{
printf("client accept error\n");
return -1;
}
printf("client: %d\n", client);
do
{
r = recv(client, buf, sizeof(buf), 0);
if( r > 0 )
{
printf("Receive: %s\n", buf);
if( strcmp(buf, "quit") != 0 )
{
len = send(client, buf, r, 0);
}
else
{
break;
}
}
} while ( r > 0 );
closesocket(client);
}
closesocket(server);
WSACleanup();
return 0;
}
Question: Is select() specific to Linux systems?
select() function under Windows
- The select() function is also provided in Windows, and the parameters are exactly the same as the Linux version
- Note: In the select() function on Windows, the first parameter has no meaning (just for compatibility)
#include <winsock2.h>
int select(int nfds, fd_set *readfds,
fd_set *writefds,
fd_set *excepfds,
const struct timeval *timeout);
One nuance: select() in Windows is designed specifically for sockets
- fd_count is used to record the number of interested sockets
- fd_array is used to record interested socket handles
typedef struct fd_set {
u_int fd_count;
SOCKET fd_array[FD_SETSIZE];
}fd_set;
Example of using the select() function in Windows
temps = reads;
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
num = select(0, &temps, 0, 0, &timeout);
if (num > 0) {
unsigned int i = 0;
for (i=0; i <reads.fd_fount; ++i) {
if (FD_ISSET(reads.fd_array[i], &temps)) {
if (reads.fd_array[i] == server) {
}
else {
}
}
}
}
Programming Lab: Multiplexing Server in Windows
// Select-Server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
SOCKET server_handler(SOCKET server)
{
struct sockaddr_in addr = {0};
int asize = sizeof(addr);
return accept(server, (struct sockaddr*)&addr, &asize);
}
int client_handler(SOCKET client)
{
char buf[32] = {0};
int ret = recv(client, buf, sizeof(buf)-1, 0);
if( ret > 0 )
{
buf[ret] = 0;
printf("Receive: %s\n", buf);
if( strcmp(buf, "quit") != 0 )
{
ret = send(client, buf, ret, 0);
}
else
{
ret = -1;
}
}
return ret;
}
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET server = 0;
struct sockaddr_in saddr = {0};
// unsigned int max = 0;
int num = 0;
fd_set reads = {0};
fd_set temps = {0};
struct timeval timeout = {0};
WSADATA wd = {0};
if( WSAStartup(MAKEWORD(2, 2), &wd) != 0 )
{
printf("startup error\n");
return -1;
}
server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if( server == INVALID_SOCKET )
{
printf("server socket error\n");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR )
{
printf("server bind error\n");
return -1;
}
if( listen(server, 1) == SOCKET_ERROR )
{
printf("server listen error\n");
return -1;
}
printf("server start success\n");
FD_ZERO(&reads);
FD_SET(server, &reads);
// max = server;
while( 1 )
{
temps = reads;
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
// num = select(max+1, &temps, 0, 0, &timeout);
num = select(0, &temps, 0, 0, &timeout);
if( num > 0 )
{
unsigned int i = 0;
for(i=0; i<reads.fd_count; i++) // 此处相对 Linux 的优势,只需遍历实际监听的 socket 句柄数量!!
{
SOCKET sock = reads.fd_array[i];
if( FD_ISSET(sock, &temps) )
{
if( sock == server )
{
SOCKET client = server_handler(sock);
if( client != INVALID_SOCKET )
{
FD_SET(client, &reads);
// max = (client > max) ? client : max;
printf("accept client: %d\n", client);
}
}
else
{
int r = client_handler(sock);
if( r == -1 )
{
FD_CLR(sock, &reads);
closesocket(sock);
}
}
}
}
}
}
closesocket(server);
WSACleanup();
return 0;
}
Thinking: How to write a network program that can be compiled and run across platforms?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。