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协议通信图解
随机推荐
- springboot2.0动态多数据源切换
摘要:springboot1.x到springboot2.0配置变化有一点变化,网上关于springboot2.0配置多数据源的资料也比较少,为了让大家配置多数据源从springboot1.x升级到s ...
- Maven下CXF的wsdl2java生成客户端代码
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin< ...
- kettle实现同构单表增量同步
job如下: 如下转换:获取区服列表,将id列表保存到结果(内存) job: 同构数据库单表抽取(每个输入执行一次) 同构数据库单表抽取(job) 的具体实现如下: 转换:获取数据库连接ID 从结果获 ...
- 201772020113李清华《面向对象程序设计(java)》第一周学习总结
201772020113<面向对象程序设计(java)>第一周学习总结 第一部分:课程准备部分 填写课程学习 平台注册账号, 平台名称 注册账号 博客园:www.cnblogs.com b ...
- CentOS内网机器利用iptables共享公网IP上网
公司有个业务是2B的以及日活不大,所以两台服务器搞定,一个6M EIP.两台机器都是CentOS7系统EIP为 xxx.xxx.xxx.xxx绑在 内网ip为 172.18.30.175的服务器上,内 ...
- CSS 图像
CSS 图像 <上一节下一节> 通过CSS可以控制图像的大小和对齐方式. 图像大小 虽然在HTML中,img标签有属性height.width设置高和宽,在工作中却使用得非常少,通常使用C ...
- CentOS7下安装Gitlab社区版【安装步骤、IP改域名、修改端口】
这两天一直在给公司的服务器配置Gitlab(10.5.4).过程很是痛苦,所以把过程记录一下. 1.安装CentOS7 从官网上下载了最新版CentOS-7-x86_64-DVD-1708.iso.用 ...
- 将Promise融会贯通之路
前端初学者经常会问,我如何在ajax1结束之后才启动ajax2呢?我怎么做才能在所有的ajax结束之后触发某程序呢?亦或是哎真是烦,5个ajax套在一起,原来的逻辑是什么呀! 一个稍微有点经验的前端程 ...
- OOm是否可以try catch ?
只有在一种情况下,这样做是可行的: 在try语句中声明了很大的对象,导致OOM,并且可以确认OOM是由try语句中的对象声明导致的,那么在catch语句中,可以释放掉这些对象,解决OOM的问题,继续执 ...
- node.js中express框架的基本使用
express是一个基于node.js平台的,快速,开放,极简的web开发框架. 一.安装 express npm install express --save 二.简单使用 express //引入 ...