C语言 Socket入门示例1—— 单工通信(客户端向服务器发送消息)

如果对Windows API不太熟悉、对TCP/IP通信协议不太熟悉,或者对C语言本身不太熟悉的话,学习Socket会有点难受的。以前学习操作系统的时候,被API吓怕了,很多莫名其妙的API有着多如牛毛的参数,令人费解。学习计算机网络的时候,又有那么多的协议,并且很多协议本身比较复杂,什么三次握手建立连接,什么四次握手释放链接等等,也没有学得特别透彻。更遗憾的是,以前学C的时候,误以为自己把C学会了,误以为C就那么几个头文件而已,就一个黑框子而已。

现在,经过一段时间的痛苦磨练,又有了一些新的认识:API并没有想象的那么难,只要把每个参数及返回值的含义以及各种数据类型之间的关系和转换方法弄明白了,API就可以灵活运用了。TCP/IP协议,其实对所有的通信协议都一样,不要忽略RFC文档,只要花足够的时间把协议的原理理解透了(最好自己能够随手画出来),接下来根据协议编写程序就顺理成章了。关于C/C++我过去低估了它的难度,也低估了它的功能,所以现在继续深入学习,以获得更多的精髓。

下面将一个简单的C/S架构Socket程序程序贴出来,我也Request For 大家 Comments

1、服务端(Server):

#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")	//把ws2_32.lib加到Link页的连接库
#define PORT 15001					//通信的端口(指服务器端)
#define ERROR 0
#define BUFFER_SIZE 1024			//注意:此Server端数据接收缓冲区 >= Client端数据发送缓冲区 ,否则造成缓冲区溢出
/*
	服务端原理:
		1、服务器进程创建套接字
		2、将本地地址绑定到所创建的套接字上,以三元组{<通信协议>,<IP地址>,<端口号>}在网络上标识该套接字
		3、将套接字置入监听模式,并准备接受连接请求
*/
int main()
{
	WSADATA WSAData;
	if(WSAStartup(MAKEWORD(2,0),&WSAData)==SOCKET_ERROR)  //启动winsock ,WSAStartup()函数对Winsock DLL进行初始化
	{
		printf("Socket initialize fail!\n");
		exit(1);
	}
	SOCKET sock;										//服务进程创建套接字句柄(用于监听)
	if((sock=socket(AF_INET,SOCK_STREAM,0))==ERROR)		//调用socket()函数创建一个流套接字,参数(网络地址类型,套接字类型,网络协议)
	{
		printf("Socket create!\n");
		WSACleanup();
		exit(1);
	}
	struct sockaddr_in ServerAddr;			//sockaddr_in结构用来标识TCP/IP协议下的地址,可强制转换为sockaddr结构
	ServerAddr.sin_family=AF_INET;			//sin_family字段必须设为AF_INET,表示该Socket处于Internet域
	ServerAddr.sin_port=htons(PORT);		//sin_port字段用于指定服务端口,注意避免冲突
	ServerAddr.sin_addr.s_addr=INADDR_ANY;  //sin_addr字段用于把一个IP地址保存为一个4字节的数,无符号长整型,根据不同用法还可表示本地或远程IP地址
	if(bind(sock,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr))==SOCKET_ERROR)  //调用bind()函数将本地地址绑定到所创建的套接字上,以在网络上标识该套接字
	{
		printf("Bind fail!\n");
		closesocket(sock);
		WSACleanup();
		exit(1);
	}
	printf("Server Socket Port:%d\n",ntohs(ServerAddr.sin_port));
	if(listen(sock,10)==SOCKET_ERROR)		//调用listen()函数将套接字置入监听模式并准备接受连接请求,参数(已捆绑未连接的套接字描述字,正在等待连接的最大队列长度)
	{
		printf("Listen fail!\n");
		closesocket(sock);
		WSACleanup();
		exit(1);
	}  

	SOCKET msgsock;			//创建一个新的套接字(用于接收accept函数的返回值,即表示已经接受的那个客户端的连接,进而接收Client发来的数据)
	char buf[BUFFER_SIZE];  //数据接收缓冲区
	while(1)
	{
		if((msgsock=accept(sock,(LPSOCKADDR)0,(int *)0))==INVALID_SOCKET)  //进入监听状态后,调用accept()函数接收客户端的连接请求,并把连接传给msgsock套接字,原sock套接字继续监听其他客户机连接请求
		{
			printf("Accept fail!\n");
			continue;
		}
		memset(buf,0,sizeof(buf));											//初始化数据接收缓冲区
		recv(msgsock,buf,BUFFER_SIZE,0);									//接收客户端发送过来的数据
		if(buf[0]==‘e‘ && buf[1]==‘x‘ && buf[2]==‘i‘ && buf[3]==‘t‘)		//"exit"命令,退出程序
		{
			printf("The End.\n");
			break;
		}
		printf("C:\\Socket\\Server>%s",buf);
		closesocket(msgsock);
	}  

	closesocket(sock); //关闭套接字
	WSACleanup();	   //终止对Winsock DLL的使用,并释放资源
	return 0;
}   

2、客户端(Client):

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")	//把ws2_32.lib加到Link页的连接库
//#define IP "172.18.68.243"			//在两台计算机上测试,IP为Server端的IP地址
#define IP "127.0.0.1"				//在一台计算机上测试,IP为本地回送地址
#define PORT 15001					//注意:客户端设置通信的端口 = 服务端的端口
#define BUFFER_SIZE 1024			//数据发送缓冲区大小

int main()
{
	char buf[BUFFER_SIZE];								//buf数组存放客户端发送的消息
	int inputLen;										//用于输入字符自增变量
	while(1)
	{
		printf("C:\\Socket\\Client>");
		inputLen=0;
		memset(buf,0,sizeof(buf));
		while((buf[inputLen++]=getchar())!=‘\n‘)		//输入以回车键为结束标识
		{
			;
		}
		if(buf[0]==‘e‘ && buf[1]==‘x‘ && buf[2]==‘i‘ && buf[3]==‘t‘)
		{
			printf("The End.\n");
			break;
		}  

		WSADATA WSAData;
		if(WSAStartup(MAKEWORD(2,0),&WSAData)==SOCKET_ERROR)  //WSAStartup()函数对Winsock DLL进行初始化
		{
			printf("Socket initialize fail!\n");
			continue;
		}
		SOCKET sock;											//客户端进程创建套接字
		if((sock=socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR)  //创建流套接字(与服务端保持一致)
		{
			printf("Socket create fail!\n");
			WSACleanup();
			continue;
		}  

		struct sockaddr_in ClientAddr;				//sockaddr_in结构用来标识TCP/IP协议下的地址,可强制转换为sockaddr结构
		ClientAddr.sin_family=AF_INET;				//指Internet域
		ClientAddr.sin_port=htons(PORT);			//指定服务端所预留的端口
		ClientAddr.sin_addr.s_addr=inet_addr(IP);	//指定服务端所绑定的IP地址
		if(connect(sock,(LPSOCKADDR)&ClientAddr,sizeof(ClientAddr))==SOCKET_ERROR)  //调用connect()函数,向服务器进程发出连接请求
		{
			printf("Connect fail!\n");
			closesocket(sock);
			WSACleanup();
			continue;
		}
		send(sock,buf,BUFFER_SIZE,0);				 //向服务器发送数据
		closesocket(sock);							 //关闭套接字
		WSACleanup();								//终止对Winsock DLL的使用,并释放资源,以备下一次使用
	}
	return 0;
}  

运行效果图:

(1)客户端发送

(2)服务端接收

C语言 Socket入门示例1—— 单工通信(客户端向服务器发送消息)

时间: 2024-08-05 11:12:12

C语言 Socket入门示例1—— 单工通信(客户端向服务器发送消息)的相关文章

C语言 Socket入门示例2——模拟远程CMD(客户端向服务器发送命令,服务端执行该命令)

只要把上一篇文章"C语言 Socket入门示例1"中的两段程序彻底搞懂,那么再看本文就没有任何难度了,因为仅仅是对上篇文章中服务端代码的简单修改扩充.但是简单修改过后,功能变得异常强大,犹如一个远程CMD.随着不断深入学习,功能将会变得越来越强大.欢迎大家评论指点. 1.服务端(Server): #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib")

C语言Socket-单工通信(客户端向服务器发送数据)

服务端(server) #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") //把ws2_32.lib加到Link页的连接库 #define PORT 15001 //通信的端口(指服务器端) #define ERROR 0 #define BUFFER_SIZE 1024 //注意:此Server端数据接收缓冲区 >= Client端数据发送缓冲区 ,否则造

C# Socket基础(四)之客户端向服务器发消息

private Socket socketClient;//客户端套接字,关于实例化请参考C# Socket基础(三)之客户端连接服务器和接收消息 客户端发送消息 1 /// <summary> 2 /// 发送数据到服务端 3 /// </summary> 4 private void Send() 5 { 6 if (socketClient == null) 7 { 8 9 ShowMsg("服务器未启动!"); 10 return; 11 } 12 by

C语言Socket-模拟远程CMD(客户端向服务器发送命令,服务器执行该命令)

服务端(server) #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") //把ws2_32.lib加到Link页的连接库 #define PORT 15001 //通信的端口(指服务器端) #define ERROR 0 #define BUFFER_SIZE 1024 //注意:此Server端数据接收缓冲区 >= Client端数据发送缓冲区 ,否则造

go语言快速入门 IPC之管道通信 8

熟悉Unix/C编程的应该对IPC也非常的熟悉,多进程之间的通信主要的手段有管道/信号量/共享内存/Socket等,而管道作为父子进程间进行少量数据传递的有效手段也得到了广泛的应用,在这篇文章中我们来看一下go语言中如何使用管道进行进程进行通信. 管道的使用 在linux下,管道被非常广泛地使用,一般在编程中我们实现了popen等的应用即可提供管道功能.而在命令行中使用地也非常多,|就是最为典型的管道的应用例子.shell会为|符号两侧的命令各创建一个脚本,将左侧的输出管道与右侧的输入管道进行连

Windows Socket编程示例-TCP示例程序

前面一部分是介绍,后面有示例 1.网络中进程之间如何通信? 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip地址"可以唯一标识网络中的主机,而传输层的"协议+端口"可以唯一标识主机中的应用程序(进程).这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互. 使用TCP

C语言Socket编程(计算机网络作业)

最近我计算机网络课程要做作业了,没办法跟着老师一步一步的写C语言的代码,使用的计算就是Socket通信发送消息:代码实现的功能很简单,客户端向服务器端发送消息,服务器端接收客户端发来的消息,并且输出显示到屏幕上:代码中的每个方法的返回值都应该做判断出错情况,以保证程序的稳定性,这里只是测试代码. 老师是录制的视频讲解的,其他其中使用的到的方法要求我们自己去查相关的MSDN资料库,如果有不懂的,就自己上网查. 服务器端接收代码: #include <Winsock2.h>#pragma comm

Socket 编程示例(二)

利用晚上这点闲暇时间,写了一个Socket通信的小实例,该实例包含服务器端和客户端.其基本工作流程是:当服务器启动服务以后,客户端进行连接,如果连接成功,则用户可以在发送消息框中输入待发送的消息,然后点击“Send”按钮后向服务器发送消息,服务器在收到消息后立即向该客户端发送接收成功消息.其基本效果如图1.1和图1.2所示(注:下面两幅图于次日补上):图1.1  服务器运行效果图图1.2  客户端运行效果图 现将服务器和客户端部分代码贴出来,由于代码较简单,基本没有注释,并在此特别说明,该实例仅

Socket 通信原理(Android客户端和服务器以TCP&amp;&amp;UDP方式互通)

ZERO.前言 有关通信原理内容是在网上或百科整理得到,代码部分为本人所写,如果不当,还望指教. 一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是s