27、通过visual s'tudio 验证 SOCKET编程:搭建一个TCP服务器
本文就是在windows下进行socket编程,搭建一个TCP客户端。
在visual studio下编程,首先在windows下进行初始化(这点在linux下是不需要的):
/*
初始化 Winsock
*/ #include<stdio.h>
#include<winsock2.h> #pragma comment(lib,"ws2_32.lib") int main(int argc, char *argv[])
{
WSADATA wsa; printf("\n初始化中Initialising Winsock...");
if (WSAStartup(MAKEWORD(, ), &wsa) != )//Winsock 启动或初始化winsock库,第一个为加载的版本,第二个为WSADATA结构
//WSAStartup应该与WSACleanup成对使用,WSAStartup的功能是初始化Winsock DLL,WSACleanup是来解除与Socket库的绑定并且释放Socket库所占用的系统资源。
{
printf("Failed. Error Code : %d", WSAGetLastError());
return ;
} printf("初始化成功Initialised."); return ;
}
运行结果:

可以看出winsock的环境已经搭建完成了。
下面就是创建一个套接字:
/*
Create a TCP socket
*/ #include<stdio.h>
#include<winsock2.h> #pragma comment(lib,"ws2_32.lib") //Winsock Library int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s; printf("\n初始化Initialising Winsock...");
if (WSAStartup(MAKEWORD(, ), &wsa) != )
{
printf("失败Failed. Error Code : %d", WSAGetLastError());
return ;
} printf("Initialised.\n"); if ((s = socket(AF_INET, SOCK_STREAM, )) == INVALID_SOCKET)
//函数socket()创建一个套接字并返回一个可用于其他网络命令的套接字描述符。
/*
地址系列:AF_INET(这是IP版本4)
类型:SOCK_STREAM(这意味着面向连接的TCP协议)
协议:0 [或IPPROTO_TCP,IPPROTO_UDP]
*/
{
printf("创建失败Could not create socket : %d", WSAGetLastError());
} printf("成功Socket created.\n"); return ;
}

好的,此时我们已经成功地创建了一个套接字。
下面就是通过bind绑定套接字:
#include<stdio.h>
#include<winsock2.h> #pragma comment(lib,"ws2_32.lib") //Winsock Library int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server; printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(, ), &wsa) != )
{
printf("Failed. Error Code : %d", WSAGetLastError());
return ;
} printf("Initialised.\n"); //Create a socket
if ((s = socket(AF_INET, SOCK_STREAM, )) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
} printf("Socket created.\n"); //配置sockaddr_in 结构体
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(); //Bind
if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
} puts("Bind done"); closesocket(s); return ;
}
进行调试编译,结果如下:

现在,绑定完成了,它的时间让套接字监听连接。我们将套接字绑定到特定的IP地址和特定的端口号。通过这样做,我们确保所有到这个端口号的传入数据都被这个应用程序接收。
下面进行listen对端口监听,然后accept接收得到的数据。
/*
Bind socket to port 8888 on localhost
*/ #include<stdio.h>
#include<winsock2.h> #pragma comment(lib,"ws2_32.lib") //Winsock Library int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
struct sockaddr_in server, client;
int c; printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(, ), &wsa) != )
{
printf("Failed. Error Code : %d", WSAGetLastError());
return ;
} printf("Initialised.\n"); //Create a socket
if ((s = socket(AF_INET, SOCK_STREAM, )) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
} printf("Socket created.\n"); //Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(); //Bind
if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
} puts("Bind done"); //Listen to incoming connections
if (listen(s, ) != )
{
printf("listen is error");
} //Accept and incoming connection
puts("Waiting for incoming connections..."); c = sizeof(struct sockaddr_in);
new_socket = accept(s, (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d", WSAGetLastError());
} puts("Connection accepted"); closesocket(s);
WSACleanup(); return ;
}
此时,一个客户端就搭建完成了,下面通过软件对客户端进行实验验证。
创建一个客户端


创建完成后运行称程序,点击连接按钮,可以看到如下输出

上面我们接受了一个传入的连接,但立即关闭。这不是很有成效。传入连接建立后,可以做很多事情。毕竟连接是为了沟通的目的而建立的。所以让我们用send函数回复客户。
/*
Bind socket to port 8888 on localhost
*/
#include<io.h>
#include<stdio.h>
#include<winsock2.h> #pragma comment(lib,"ws2_32.lib") //Winsock Library int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
struct sockaddr_in server, client;
int c;
char *message; printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(, ), &wsa) != )
{
printf("Failed. Error Code : %d", WSAGetLastError());
return ;
} printf("Initialised.\n"); //Create a socket
if ((s = socket(AF_INET, SOCK_STREAM, )) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
} printf("Socket created.\n"); //Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(); //Bind
if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
} puts("Bind done"); //Listen to incoming connections
listen(s, ); //Accept and incoming connection
puts("Waiting for incoming connections..."); c = sizeof(struct sockaddr_in);
new_socket = accept(s, (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d", WSAGetLastError());
} puts("Connection accepted"); //Reply to client
message = "Hello Client , I have received your connection. But I have to go now, bye\n";
send(new_socket, message, strlen(message), ); getchar(); closesocket(s);
WSACleanup(); return ;
}
同样运行程序,然后点击连接,可以看到调试软件有如下的反馈输出:

虽然有反馈了但是对客户端发送过来的数据没有recv进行显示处理,這里,将整个程序优化如下:
/*
TCP Echo server example in winsock
Live Server on port 8888
*/
#include<stdio.h>
#include<winsock2.h> #pragma comment(lib, "ws2_32.lib") //Winsock Library int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET master, new_socket, client_socket[], s;
struct sockaddr_in server, address;
int max_clients = , activity, addrlen, i, valread;
char *message = "ECHO Daemon v1.0 \r\n"; //size of our receive buffer, this is string length.
int MAXRECV = ;
//set of socket descriptors
fd_set readfds;
//1 extra for null character, string termination
char *buffer;
buffer = (char*)malloc((MAXRECV + ) * sizeof(char)); for (i = ; i < ; i++)
{
client_socket[i] = ;
} printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(, ), &wsa) != )
{
printf("Failed. Error Code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
} printf("Initialised.\n"); //Create a socket
if ((master = socket(AF_INET, SOCK_STREAM, )) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
exit(EXIT_FAILURE);
} printf("Socket created.\n"); //Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(); //Bind
if (bind(master, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
} puts("Bind done"); //Listen to incoming connections
listen(master, ); //Accept and incoming connection
puts("Waiting for incoming connections..."); addrlen = sizeof(struct sockaddr_in); while (TRUE)
{
//clear the socket fd set
FD_ZERO(&readfds); //add master socket to fd set
FD_SET(master, &readfds); //add child sockets to fd set
for (i = ; i < max_clients; i++)
{
s = client_socket[i];
if (s > )
{
FD_SET(s, &readfds);
}
} //wait for an activity on any of the sockets, timeout is NULL , so wait indefinitely
activity = select(, &readfds, NULL, NULL, NULL); if (activity == SOCKET_ERROR)
{
printf("select call failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
} //If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master, &readfds))
{
if ((new_socket = accept(master, (struct sockaddr *)&address, (int *)&addrlen))<)
{
perror("accept");
exit(EXIT_FAILURE);
} //inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); //send new connection greeting message
if (send(new_socket, message, strlen(message), ) != strlen(message))
{
perror("send failed");
} puts("Welcome message sent successfully"); //add new socket to array of sockets
for (i = ; i < max_clients; i++)
{
if (client_socket[i] == )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets at index %d \n", i);
break;
}
}
} //else its some IO operation on some other socket :)
for (i = ; i < max_clients; i++)
{
s = client_socket[i];
//if client presend in read sockets
if (FD_ISSET(s, &readfds))
{
//get details of the client
getpeername(s, (struct sockaddr*)&address, (int*)&addrlen); //Check if it was for closing , and also read the incoming message
//recv does not place a null terminator at the end of the string (whilst printf %s assumes there is one).
valread = recv(s, buffer, MAXRECV, ); if (valread == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
if (error_code == WSAECONNRESET)
{
//Somebody disconnected , get his details and print
printf("Host disconnected unexpectedly , ip %s , port %d \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); //Close the socket and mark as 0 in list for reuse
closesocket(s);
client_socket[i] = ;
}
else
{
printf("recv failed with error code : %d", error_code);
}
}
if (valread == )
{
//Somebody disconnected , get his details and print
printf("Host disconnected , ip %s , port %d \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); //Close the socket and mark as 0 in list for reuse
closesocket(s);
client_socket[i] = ;
} //Echo back the message that came in
else
{
//add null character, if you want to use with printf/puts or other string handling functions
buffer[valread] = '\0';
printf("%s:%d - %s \n", inet_ntoa(address.sin_addr), ntohs(address.sin_port), buffer);
send(s, buffer, valread, );
}
}
}
} closesocket(s);
WSACleanup(); return ;
}
运行,程序,打开仿真软件配置后点击连接,可以看到输入如下


输入数据点击发送后可以看到,输出如下:


至此,一个功能基本完备的服务器已经搭建完成了,但是其实这个服务器还是不完善的,这个将在下片文章中进行说明。
下篇文章:
vSocket模型详解及select应用详解
27、通过visual s'tudio 验证 SOCKET编程:搭建一个TCP服务器的更多相关文章
- 利用socket编程在ESP32上搭建一个TCP客户端
通过之前http://www.cnblogs.com/noticeable/p/7636582.html中对socket的编程,已经可以知道如何通过socket编程搭建服务器和客户端了,现在,就在ES ...
- Windows下C语言的Socket编程例子(TCP和UDP)
原文:Windows下C语言的Socket编程例子(TCP和UDP) 刚刚学windows编程,所以想写学习笔记,这是一个简单的Socket程序例子,开发环境是vc6: 首先是TCP server端: ...
- 5.1 socket编程、简单并发服务器
什么是socket? socket可以看成是用户进程与内核网络协议栈的编程接口.是一套api函数. socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机间的进程间通信. 工业上使用的为t ...
- 使用socket编程实现一个简单的文件服务器
使用socket编程实现一个简单的文件服务器.客户端程序实现put功能(将一个文件从本地传到文件服务器)和get功能(从文件服务器取一远程文件存为本地文件).客户端和文件服务器不在同一台机器上. pu ...
- 使用Java Socket手撸一个http服务器
原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...
- Socket编程基础——面向连接TCP
WinSock是Windows环境下的网络编程接口,它最初是基于Unix环境下的BSD Socket,是一个与网络协议无关的编程接口.WinSock包含两个主要版本,即WinSock1和WinSock ...
- C# Socket编程(5)使用TCP Socket
TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer) ...
- socket编程:客户端与服务器间的连接以及各函数的用法
在认真的看UNP之前,一直被socket编程说的云里雾里,今天我要让大家从整天上认识socket编程,让我们知道socket编程的整个流程和各个函数的用法.这样:我们在写一些简单的socket编程时就 ...
- 《java入门第一季》之Socket编程通信和TCP协议通信图解
Socket编程通信图解原理: TCP协议通信图解
随机推荐
- Servlet的几个关键知识点
1.ServletConfig ServletConfig是Servlet的配置文件.对应于web.xml中的<servlet></servlet>标签.ServletConf ...
- 一致性hash算法及java实现
一致性hash算法是分布式中一个常用且好用的分片算法.或者数据库分库分表算法.现在的互联网服务架构中,为避免单点故障.提升处理效率.横向扩展等原因,分布式系统已经成为了居家旅行必备的部署模式,所以也产 ...
- issue_hana
2019-01-11T14:35:01.910187+08:00 SHADEVDB01 cron[57062]: PAM unable to dlopen(/lib64/security/pam_sy ...
- Openface 入门
Openface 简单入门 背景 Openface是一个开源的人脸识别框架,同类软件产品还有 seetaface ,DeepID等,当然,如果算上商业的产品,那就更多了. Openface人脸比对结果 ...
- Spring系列之Spring常用注解总结 转载
Spring系列之Spring常用注解总结 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点:1.如果所有的内容都配置在.xml文件中,那么.x ...
- R语言-图的要素颜色
1.设置图形要素的颜色 Plot函数中,使用col=参数来决定要素的颜色 如果不指定plot type,颜色加在散点上,如果指定了plot type,例如line,则颜色加在线上 其它函数,例如bar ...
- 获取当前页面url
function getCurrUrl() { var url = ""; if (parent !== window) { try { url = window.top.loca ...
- react-native 新手爬坑经历(Could not connect to development server.)
来,先说下报错出现场景,刚跑完项目加载完是好的,但是双击R后就开始耍小脾气了-红屏出现,如下图 首先检查包服务器是否运行正常.在项目文件夹下输入react-native start或者npm star ...
- Lua中面向对象
一.Lua中类的简单实现: (1)版本——摘自 Cocos2.0中的: --Create an class. function class(classname, super) local superT ...
- window.innerWidth和document.body.clientWidth的区别
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...