Hello,大家好,这次写的socket网络编程 是关于服务端与客户端通信之简单协议的实现 , 当然这是应用层的协议 。
很简单,具体的通信过程是 客户端给服务端传送( 操作数个数 操作数 和 操作符),而服务端接收到数据后,进行解析并计算,最后将计算结果发送给客户端,这只能是很多复杂协议的最简单版本了,主要是通过简单来看透复杂的东西,将复杂看简单。Talk is cheap , show me the code.
server.c
#include<stdlib.h>
#include<stdio.h>
#include<WinSock2.h>
#define BUF_SIZE 1024
#pragma comment(lib,"ws2_32.lib")
int main(){
WSADATA wsd;
SOCKET sServer, sClient;
SOCKADDR_IN addrServer, addrClient;
int recvCount = 100;
int sizeAddrClient = 0;
char sendBuf[BUF_SIZE];
char recvBuf[BUF_SIZE];
int opMsg[1024] = {0};
const int OPSZ = 4;
//初始化socket库
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){
ErrorHandling("WSAStartup error!");
}
puts("初始化socket库");
//创建服务端socket
sServer = socket(AF_INET, SOCK_STREAM, 0);
if (sServer == INVALID_SOCKET){
ErrorHandling("socket() error!");
}
puts("创建服务端socket");
//初始化网络地址信息
memset(&addrServer, 0, sizeof(addrServer));
addrServer.sin_family = AF_INET;
addrServer.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
addrServer.sin_port = htons(6000);
puts("初始化网络地址信息");
//绑定地址信息到服务端socket
if (bind(sServer, (SOCKADDR*)&addrServer, sizeof(addrServer)) == SOCKET_ERROR){
ErrorHandling("bind() error!");
}
puts("绑定地址信息到服务端socket");
//服务端进行监听
if (listen(sServer, 5) == SOCKET_ERROR){
ErrorHandling("listen() error!");
}
puts("服务端进行监听ing");
sizeAddrClient = sizeof(addrClient);
//服务端进入接收消息状态(阻塞模式)
sClient = accept(sServer, (SOCKADDR*)&addrClient, &sizeAddrClient);
if (sClient == INVALID_SOCKET){
ErrorHandling("accept() error!");
}
printf("有用户连接:%s\n", inet_ntoa(addrClient.sin_addr));
char operator = '\0';
//循环接收消息(我规定最多为200次)
while (recvCount>0){
memset(recvBuf, 0, BUF_SIZE);
memset(recvBuf, 0, BUF_SIZE);
int recvNum = recv(sClient, recvBuf, 1024, 0);
if (recvNum == -1){
printf("exit\n");
break;
}
//获取操作数个数
int opt_num = (char)recvBuf[0];
//获取操作数,存入opMsg数组中
int i = 0;
for (i = 0; i < opt_num;i++){
memcpy(&opMsg[i], &recvBuf[OPSZ * i + 1], OPSZ);
}
//获取操作符
char operator = recvBuf[i*OPSZ + 1];
printf("%c",operator);
//根据操作符计算结果
int results = 0;
switch (operator){
case '+':
results = 0;
for (i = 0; i < opt_num;i++){
results += opMsg[i];
}
break;
case '-':
results = opMsg[0];
for (i = 1; i < opt_num; i++){
results -= opMsg[i];
}
break;
case '*':
results =1 ;
for (i = 0; i < opt_num; i++){
results *= opMsg[i];
}
break;
default:
ErrorHandling("错误的操作符!");
}
//将结果数据复制到charBuf前4个字节中,并发送给客户端
memcpy(sendBuf, &results, OPSZ);
send(sClient, sendBuf, OPSZ, 0);
recvCount--;
}
//关闭socket
closesocket(sClient);
closesocket(sServer);
WSACleanup();
puts("关闭socket");
system("pause");
return 0;
}
client.c
#include<stdlib.h>
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define BUF_SIZE 1024
void ErrorHandling(char * msg){
puts(msg);
system("pause");
exit(1);
}
int main2(){
WSADATA wsd;
SOCKET sClient;
SOCKADDR_IN addrClient;
int sizeAddrClient = 0;
int recvCount = 100;
char charBuf[BUF_SIZE] = { 0 };
const int OPSZ = 4;
//初始化socket库
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){
ErrorHandling("WSAStartup error!");
}
puts("初始化socket库");
//创建客户端socket
sClient = socket(AF_INET, SOCK_STREAM, 0);
if (sClient == INVALID_SOCKET){
ErrorHandling("socket() error!");
}
puts("创建客户端socket");
//初始化网络地址信息
memset(&addrClient, 0, sizeof(addrClient));
addrClient.sin_family = AF_INET;
addrClient.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrClient.sin_port = htons(6000);
puts("初始化网络地址信息");
//连接服务端
if (connect(sClient, (SOCKADDR*)&addrClient, sizeof(addrClient)) == SOCKET_ERROR){
ErrorHandling("connect error!");
}
puts("现在可以向服务端发送消息");
int recvNum = 0;
char charRecv[BUF_SIZE];
char opMsg[BUF_SIZE];
int i = 0;
//循环发送消息(我规定最多为200次)
while (recvCount>0){
memset(opMsg, 0, BUF_SIZE);
memset(charRecv, 0, 1024);
//输入操作数的个数
printf("输入操作数的个数:");
int opt_num = 0;
scanf("%d",&opt_num);
//将输入的个数 存入第一个字节中,因为不需要太大
opMsg[0] = (char)opt_num;
//输入每一个操作数(注意类型转换)
for (i = 0; i < opt_num; i++){
printf("Operand %d:",i+1);
scanf("%d", (int *)&opMsg[i*OPSZ+1]);
}
//清理一下标准输入 , 如果不清理,下面操作符就直接存入'回车'了。
fflush(stdin);
printf("Operator:");
//输入操作符
scanf("%c",&opMsg[i*OPSZ]+1);
fflush(stdin);
//将字符数组发送至服务端
/*
这里有必要说一下服务端与客户端传输的数据格式
第一个字节:操作数的个数
第2-5 字节:第一个操作数
第6-9 字节:第二个操作数
以此类推
最后一个操作数的下一个字节(也就是格式中的最后一个字节):操作符(*,+,-)
*/
//opt_num*OPSZ+2 也就是操作数个数*每个操作数所占字节数+一个操作数个数+一个操作符
int sendLen = send(sClient, opMsg, opt_num*OPSZ + 2, 0);
//发送完成之后,就接收计算结果了 4个字节的整数,放到charRecv中
recv(sClient, charRecv, OPSZ, 0);
int results = 0;
//将charRecv 前4个字节的数据 复制到 results中
memcpy(&results, charRecv, OPSZ);
printf("results:%d\n", results);
recvCount--;
}
//关闭socket
closesocket(sClient);
WSACleanup();
puts("关闭socket");
system("pause");
return 0;
}
注释很完整了,如有不明白之处,请回复。
之后我会继续为大家带来简单易懂的socket程序。