socket服务器其实网上有很多的代码,但是大部分是基于Linux的,或者是Windows下的c++语言完成的设计,而且大部分是一对一的连接。今天发表一个C语言完成的socket服务器,可以实现一对多,多个客户端可以用IP和发送的数据来区分不同。另外,我的多客户端不是选择进程和多线程的办法,但是对于有需要的,我会添加线程和进程的使用。
注意:这是vs2017的环境,但是对于Windows大部分的编译器来说,是没有问题的,如果不行,对于报错的信息进行修改就可以了。如果是Linux的系统下,需要改的稍微多一点,但是万变不离其宗,基本上就是头文件名,参数和函数名的修改,整体的结构是我实验了很多次的。
1.socket服务器的代码 (一对一)
#include"pch.h"
#include <stdio.h>
#include <winsock2.h>
//#include<iostream>
//#define MaxSize 10000
#pragma comment(lib,"ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS//解决:inet_ntoa函数和无法使用inet_ntop的问题
int main(int argc, char* argv[])
{
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);//操作系统根据请求的Socket版本来搜索相应的Socket库,
//然后绑定找到的Socket库到该应用程序中。
//以后应用程序就可以调用所请求的Socket库中的其它Socket函数
WSADATA wsaData;//WSADATA是一种数据结构,存储WSAStartup函数返回的数据
if (WSAStartup(sockVersion, &wsaData) != 0)//第一个参数是版本号,第二个参数是保存start的返回值
{
return 0;
}
//创建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建面向网络的套接字,而且是有连接的,协议自然为TCP协议
if (slisten == INVALID_SOCKET)//判断套接字是否创建成功
{
printf("socket error !");
return 0;
}
//绑定IP和端口
sockaddr_in sin;//处理网络通信地址的结构体,声明变量
sin.sin_family = AF_INET;// TCP/IP协议族
sin.sin_port = htons(80);//端口可以自己赋值
sin.sin_addr.S_un.S_addr = INADDR_ANY;//设置的是服务器的IP地址,inet_addr("0.0.0.0"); 本地的IP地址是
//服务器端计算机上的所有网卡的IP地址都可以作为服务器IP地址
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)//绑定并进行判断,套接字指向sockaddr_in结构体的指针,参数长度
{
printf("bind error !");
}
for (int i=0; i<10;i++)
{//开始监听
if (listen(slisten, 10) == SOCKET_ERROR)//监听一个主动连接的套接字,一个队列内核上限(slisten 变为监听套接字)
{
printf("listen error !");
return 0;
}
//循环接收数据
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
printf("等待连接...\n");
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);//返回值:连接套接字;参数:监听套接字,ADDR结构体,ADDR结构体的大小
if (sClient == INVALID_SOCKET)//为空,继续
{
printf("accept error !");
//continue;
}
printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
while (true)
{
//接收数据
int ret = recv(sClient, revData, 1024, 0);//指定套接字,接收的数据,buf,一般为0
//printf("%s", &revData);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);//显示接收的数据
printf("\n");
}
//发送数据
const char * sendData = revData;//对于客户端发送过来的数据,再原样反馈回去。
send(sClient, sendData, strlen(sendData), 0);//参数说明:套接字,发送数据,长度,一般为0
if (sClient == INVALID_SOCKET)//为空,继续
{
printf("listen error !");
break;
}
// closesocket(sClient);
}
closesocket(sClient);
}
closesocket(slisten);//关闭
WSACleanup();//清除
return 0;
}
这是一对一连接成功的结果图,有问题的可以联系我。
代码编译的控制台 一个仿真软件做客户端,也可以自己写
2.进程的使用方法
/*如果想使用多线程,可以在原有的基础上进行新的函数定义,然后用下面的办法创建,其中会有一些声明和变量的定义,可以通过编译器的报错来修改,基本上没有什么大问题了。当然,你要使用互斥锁可能难度更大一些*/
HANDLE hThread01 = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)send, (LPVOID)sClient, 0, 0);//发送,send就是你所编辑的函数,可以替换,sclient就是你的创建的接收的数据套接字,也可修改
if (hThread1 != NULL)
{
CloseHandle(hThread1);
}
HANDLE hThread02 = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)recv, (LPVOID)sClient, 0, 0);//接收,类比第一个线程
if (hThread2 != NULL)
{
CloseHandle(hThread2);
}
Sleep(1000); //must
3.一对多服务器,可以打开多个客户端连接
在一对一的基础上,可以使用线程的办法,实现一个服务器多个客户端,但是线程挺难的,所以说,我没有理解透彻,就换了一个办法,在Windows的环境下可以,在Linux的环境下,稍微修改一下头文件和函数名也可以实现。我这里给出Windows下一对多的服务器代码。
服务器的代码网址:https://download.csdn.net/download/jinfu5225/12342650
客户端是用的sscom仿真软件,这样的话,比较方便,有需要的下载:https://download.csdn.net/download/jinfu5225/12342561