基于UDP的socket程序,多线程操作,windows下C语言

合集下载

基于UDP协议的WinSock编程

基于UDP协议的WinSock编程

WinSocket 编程(基于UDP)对于在一个无连接套接字上接收数据的进程来说,步骤并不复杂。

先用WSAStartup来加载Winscock DLL相应版本,然后用socket或WSASocket建立套接字。

再把这个套接字和准备接收数据的接口绑定在一起。

这是通过b i n d函数来完成的。

和面向连接会话不同的是,我们不必调用l i s t e n和a c c e p t。

1、Winsock的初始化每个Wi n s o c k应用都必须加载Winsock DLL的相应版本。

如果调用Wi n s o c k之前,没有加载Wi n s o c k库,这个函数就会返回一个S O C K E T _ E R R O R,错误信息是W S A N O T I N I T I A L I S E D。

加载Wi n s o c k库是通过调用W S A S t a r t u p函数实现的。

这个函数的定义如下:int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);wVersionRequested[in] Highest version of Windows Sockets support that the caller can use. The high-order byte specifies the minor version (revision) number; the low-order byte specifies the major version number.lpWSAData[out] Pointer to the WSADATA data structure that is to receive details of the Windows Sockets implementation.The WSAStartup function returns zero if successful. Otherwise, it returns one of the error codes listed in the following. An application cannot call WSAGetLastError to determine the error code as is normally done in Windows Sockets if WSAStartup fails. The Ws2_32.dll will not have been loaded in the case of a failure so the client data area where the last error information is stored could not be established.Error code MeaningWSASYSNOTREADY Indicates that the underlying network subsystem is not ready for network communication.WSA VERNOTSUPPORTED The version of Windows Sockets support requested is not provided by this particular Windows Sockets implementation.WSAEINPROGRESS A blocking Windows Sockets 1.1 operation is in progress. WSAEPROCLIM Limit on the number of tasks supported by the Windows Sockets implementation has been reached.WSAEFAULT The lpWSAData is not a valid pointer.注释:The WSAStartup function must be the first Windows Sockets function called by an application or DLL. It allows an application or DLL to specify the version of Windows Sockets required and retrieve details of the specific Windows Sockets implementation. The application orDLL can only issue further Windows Sockets functions after successfully calling WSAStartup. (在使用Windows Sockets 之前必须调用WSAStartup 加载Winsocket库成功)Once an application or DLL has made a successful WSAStartup call, it can proceed to make other Windows Sockets calls as needed. When it has finished using the services of the Ws2_32.dll, the application or DLL must call WSACleanup to allow the Ws2_32.dll to free any resources for the application.(在使用完Ws2_32.dll需要调用WSACleanup )int WSACleanup (void);例子:The following code fragment demonstrates how an application that supports only version 2.2 of Windows Sockets makes a WSAStartup call:WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 2, 2 );/*wVersionRequested参数用于指定准备加载的Winsock库的版本。

Windows下C语言的Socket编程例子(TCP和UDP)

Windows下C语言的Socket编程例子(TCP和UDP)

Windows下C语言的Socket编程例子(TCP和UDP)sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);基于TCP的socket编程是采用的流式套接字。

在这个程序中,将两个工程添加到一个工作区。

要链接一个ws2_32.lib的库文件。

服务器端编程的步骤:1:加载套接字库,创建套接字(WSAStartup()/socket());2:绑定套接字到一个IP地址和一个端口上(bind());3:将套接字设置为监听模式等待连接请求(listen());4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());5:用返回的套接字和客户端进行通信(send()/recv());6:返回,等待另一连接请求;7:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

客户端编程的步骤:1:加载套接字库,创建套接字(WSAStartup()/socket());2:向服务器发出连接请求(connect());3:和服务器端进行通信(send()/recv());4:关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

函数介绍:1.#include<sys/socket.h>int socket (int family, int type, int protocol);返回值,成功为非负整数,成为套接口描数字;出错为-1、family参数:AF_INET --ipv4;AF_INET6--ipv6;AF_LOCAL--unix域协议;AF_ROUTE--路由socket;AF_KEY--密钥socket;type参数:SOCK_STREAM--字节流套接口SOCK_DGRAM--数据报套接口SOCK_RAM--原始套接口protocal参数一般置为0,当type为SOCK_RAM时不同2.#include<sys/socket.h>int connect (int sockfd, const struct sockaddr* servaddr, socklen_t addlen);返回值,0-成功;-1-出错;servaddr参数可以为sockaddr_in和sockaddr_in6类型,但是都必须强制转化为sockaddr指针类型;connect函数的出错处理:(1)ETIMEOUT-connection timed out 目的主机不存在,没有返回任何相应,例如主机关闭(2)ECONNREFUSED-connection refused(硬错)到达目的主机后,由于各种原因建立不了连接,主机返回RST(复位)响应,例如主机监听进程未启用,tcp取消连接等(3)EHOSTTUNREACH-no route to host(软错)路由上引发了一个目的地不可达的ICMP错误其中(1)(3),客户端会进行定时多次重试,一定次数后才返回错误。

windows环境下C语言多线程实现网络编程多人聊天室

windows环境下C语言多线程实现网络编程多人聊天室

windows环境下C语言多线程实现网络编程多人聊天室在Windows环境下使用C语言实现多线程网络编程的多人聊天室是一个非常有趣和具有挑战性的项目。

在本文中,我将向您介绍如何使用C语言和Windows API来实现这样一个聊天室,并提供一些关键的代码示例。

首先,我们需要了解一些基本的网络编程概念。

在本例中,我们将使用TCP协议进行通信,因为它是一种可靠的协议,适用于需要确保数据传输完整性和顺序的场景。

要实现多人聊天室,我们需要一个服务器和多个客户端。

服务器将负责接收来自客户端的连接请求,并将消息广播给其他客户端。

客户端将负责连接到服务器,并发送和接收消息。

下面是一个简化的服务器代码示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <winsock2.h>#define MAX_CLIENTS 10#define BUFFER_SIZE 1024DWORD WINAPI ClientHandler(LPVOID lpParam);int maiWSADATA wsaData;SOCKET serverSocket, clientSocket;struct sockaddr_in serverAddr, clientAddr;HANDLE threadHandles[MAX_CLIENTS];int clientCount = 0;// 初始化Winsockif (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)printf("Failed to initialize winsock.\n");return 1;}//创建服务器套接字serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverSocket == INVALID_SOCKET)printf("Failed to create server socket.\n");return 1;}//设置服务器地址和端口serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = INADDR_ANY;serverAddr.sin_port = htons(8888);//绑定服务器套接字到指定地址和端口if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)printf("Failed to bind server socket.\n");return 1;}//监听客户端连接请求if (listen(serverSocket, 5) == SOCKET_ERROR)printf("Failed to listen on server socket.\n");return 1;}printf("Server started. Waiting for connections...\n");while (1)//接受客户端连接请求int clientAddrSize = sizeof(clientAddr);clientSocket = accept(serverSocket, (structsockaddr*)&clientAddr, &clientAddrSize);if (clientSocket == INVALID_SOCKET)printf("Failed to accept client connection.\n");continue;}//创建线程处理客户端threadHandles[clientCount] = CreateThread(NULL, 0, ClientHandler, (LPVOID)clientSocket, 0, NULL);if (threadHandles[clientCount] == NULL)printf("Failed to create client handler thread.\n");closesocket(clientSocket);continue;}clientCount++;printf("Client connected. Total clients: %d\n", clientCount);}//关闭服务器套接字closesocket(serverSocket);// 清理WinsockWSACleanup(;return 0;DWORD WINAPI ClientHandler(LPVOID lpParam)SOCKET clientSocket = (SOCKET)lpParam;char buffer[BUFFER_SIZE];int bytesRead;while (1)//接收客户端消息bytesRead = recv(clientSocket, buffer, BUFFER_SIZE, 0);if (bytesRead <= 0)break;}//广播消息给其他客户端for (int i = 0; i < clientCount; i++)if (threadHandles[i] != NULL && threadHandles[i] != GetCurrentThread()send(threadHandles[i], buffer, bytesRead, 0);}}}//关闭客户端套接字closesocket(clientSocket);return 0;```上述代码包含一个主函数`main`和一个客户端处理函数`ClientHandler`。

基于udp socket编程实现

基于udp socket编程实现

基于udp socket编程实现一、UDP协议简介UDP(User Datagram Protocol)是一种无连接的传输层协议,它不保证数据传输的可靠性,但具有实时性和高效性等特点。

UDP协议主要用于音视频传输、网络游戏等场景。

二、UDP Socket编程概述Socket是一种通信机制,它是应用程序与网络之间的接口。

UDP Socket编程就是利用Socket接口进行UDP通信的过程。

在Python 中,可以使用socket模块进行UDP Socket编程。

三、Python socket模块介绍Python中的socket模块提供了一个简单而强大的接口来创建和使用套接字(socket)。

通过socket模块,我们可以创建TCP套接字和UDP套接字,并通过这些套接字进行网络通信。

四、Python UDP Socket编程实现步骤1. 创建UDP套接字:使用socket.socket()函数创建一个新的套接字,并指定协议族为AF_INET(IPv4),类型为SOCK_DGRAM(UDP)。

2. 绑定端口:使用bind()函数将套接字绑定到指定的IP地址和端口号。

3. 发送数据:使用sendto()函数向指定IP地址和端口号发送数据。

4. 接收数据:使用recvfrom()函数从指定IP地址和端口号接收数据。

五、Python UDP Socket编程实例下面是一个简单的Python UDP Socket编程实例,实现了一个简单的UDP客户端和服务器端的通信。

1. 服务器端代码:import socket# 创建UDP套接字server_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# 绑定IP地址和端口号server_socket.bind(('127.0.0.1', 8000))print('服务器已启动,等待客户端连接...')while True:# 接收数据data, addr = server_socket.recvfrom(1024)print('接收到来自{}的消息:{}'.format(addr, data.decode()))# 发送数据server_socket.sendto('Hello, {}'.format(addr).encode(), addr)2. 客户端代码:import socket# 创建UDP套接字client_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)# 发送数据client_socket.sendto('Hello, Server'.encode(), ('127.0.0.1', 8000))# 接收数据data, addr = client_socket.recvfrom(1024)print('接收到来自{}的消息:{}'.format(addr, data.decode()))六、总结本文介绍了UDP协议的基本概念和Python UDP Socket编程实现步骤,以及给出了一个简单的Python UDP Socket编程实例。

C语言socket编程----实现UDP通信

C语言socket编程----实现UDP通信

C语⾔socket编程----实现UDP通信TCP/IP协议叫做传输控制/⽹际协议,⼜叫做⽹络通信协议。

实际上,它包括上百个功能的协议。

套接字(socket):在⽹络中⽤来描述计算机中不同程序与其他计算程序的通信⽅式。

套接字分为三类;流式socket(SOCK_STREAM):提供可靠,⾯向连接的通信流;它使⽤TCP协议,从⽽保证了数据传输的正确性和顺序性。

数据报socket(SOCK_DGRAM):数据报套接字定义了⼀种⽆连接的服务,数据通过相互独⽴的报⽂进⾏传输,⽆序的,并且不保证可靠,⽆差错的。

它使⽤的数据报协议是UDP。

原始socket:原始套接字允许对底层协议如TP或ICMP进⾏直接访问,它功能强⼤但使⽤复杂,主要⽤于⼀些协议的开发。

下⾯是UDP通信的demo://socket udp 服务端1 #include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 #include<sys/socket.h>5 #include<arpa/inet.h>67int main()8 {9//创建socket对象10int sockfd=socket(AF_INET,SOCK_DGRAM,0);1112//创建⽹络通信对象13struct sockaddr_in addr;14 addr.sin_family =AF_INET;15 addr.sin_port =htons(1324);16 addr.sin_addr.s_addr=inet_addr("127.0.0.1");1718//绑定socket对象与通信链接19int ret =bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));20if(0>ret)21 {22 printf("bind\n");23return -1;2425 }26struct sockaddr_in cli;27 socklen_t len=sizeof(cli);2829while(1)30 {31char buf =0;32 recvfrom(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&cli,&len);33 printf("recv num =%hhd\n",buf);3435 buf =66;36 sendto(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&cli,len);3738 }39 close(sockfd);4041 }//socket udp 客户端1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/socket.h>4 #include<unistd.h>5 #include<arpa/inet.h>67int main()8 {9//创建socket对象10int sockfd=socket(AF_INET,SOCK_DGRAM,0);1112//创建⽹络通信对象13struct sockaddr_in addr;14 addr.sin_family =AF_INET;15 addr.sin_port =htons(1324);16 addr.sin_addr.s_addr = inet_addr("192.168.0.143");1718while(1)19 {20 printf("请输⼊⼀个数字:");21char buf=0;22 scanf("%hhd",&buf);23 sendto(sockfd,&buf,24sizeof(buf),0,(struct sockaddr*)&addr,sizeof(addr));2526 socklen_t len=sizeof(addr);27 recvfrom(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&addr,&len); 2829if(66 ==buf)30 {31 printf(" server 成功接受\n");32 }33else34 {35 printf("server 数据丢失\n");36 }3738 }39 close(sockfd);4041 }。

Windows下C语言的Socket编程例子(TCP和UDP)

Windows下C语言的Socket编程例子(TCP和UDP)

Windows下C语⾔的Socket编程例⼦(TCP和UDP)⼀。

<TCP>server端:1 #include "stdafx.h"2 #include <stdio.h>3 #include <winsock2.h>45#pragma comment(lib,"ws2_32.lib")67int main(int argc, char* argv[])8 {9//初始化WSA10 WORD sockVersion = MAKEWORD(2,2);11 WSADATA wsaData;12if(WSAStartup(sockVersion, &wsaData)!=0)13 {14return0;15 }1617//创建套接字18 SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);19if(slisten == INVALID_SOCKET)20 {21 printf("socket error !");22return0;23 }2425//绑定IP和端⼝26 sockaddr_in sin;27 sin.sin_family = AF_INET;28 sin.sin_port = htons(8888);29 sin.sin_addr.S_un.S_addr = INADDR_ANY;30if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)31 {32 printf("bind error !");33 }3435//开始监听36if(listen(slisten, 5) == SOCKET_ERROR)37 {38 printf("listen error !");39return0;40 }4142//循环接收数据43 SOCKET sClient;44 sockaddr_in remoteAddr;45int nAddrlen = sizeof(remoteAddr);46char revData[255];47while (true)48 {49 printf("等待连接...\n");50 sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);51if(sClient == INVALID_SOCKET)52 {53 printf("accept error !");54continue;55 }56 printf("接受到⼀个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));5758//接收数据59int ret = recv(sClient, revData, 255, 0);60if(ret > 0)61 {62 revData[ret] = 0x00;63 printf(revData);64 }6566//发送数据67char * sendData = "你好,TCP客户端!\n";68 send(sClient, sendData, strlen(sendData), 0);69 closesocket(sClient);70 }7172 closesocket(slisten);73 WSACleanup();74return0;75 }client端:1 #include "stdafx.h"2 #include <WINSOCK2.H>3 #include <STDIO.H>45#pragma comment(lib,"ws2_32.lib")678int main(int argc, char* argv[])9 {10 WORD sockVersion = MAKEWORD(2,2);11 WSADATA data;12if(WSAStartup(sockVersion, &data) != 0)13 {14return0;15 }1617 SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);18if(sclient == INVALID_SOCKET)19 {20 printf("invalid socket !");21return0;22 }2324 sockaddr_in serAddr;25 serAddr.sin_family = AF_INET;26 serAddr.sin_port = htons(8888);27 serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");28if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)29 {30 printf("connect error !");31 closesocket(sclient);32return0;33 }34char * sendData = "你好,TCP服务端,我是客户端!\n";35 send(sclient, sendData, strlen(sendData), 0);3637char recData[255];38int ret = recv(sclient, recData, 255, 0);39if(ret > 0)40 {41 recData[ret] = 0x00;42 printf(recData);43 }44 closesocket(sclient);45 WSACleanup();46return0;47 }⼆. <UDP>SERVER 端1 #include "stdafx.h"2 #include <stdio.h>3 #include <winsock2.h>45#pragma comment(lib, "ws2_32.lib")67int main(int argc, char* argv[])8 {9 WSADATA wsaData;10 WORD sockVersion = MAKEWORD(2,2);11if(WSAStartup(sockVersion, &wsaData) != 0)12 {13return0;14 }1516 SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);17if(serSocket == INVALID_SOCKET)18 {19 printf("socket error !");20return0;21 }2223 sockaddr_in serAddr;24 serAddr.sin_family = AF_INET;25 serAddr.sin_port = htons(8888);26 serAddr.sin_addr.S_un.S_addr = INADDR_ANY;27if(bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)28 {29 printf("bind error !");30 closesocket(serSocket);31return0;32 }3334 sockaddr_in remoteAddr;35int nAddrLen = sizeof(remoteAddr);36while (true)37 {38char recvData[255];39int ret = recvfrom(serSocket, recvData, 255, 0, (sockaddr *)&remoteAddr, &nAddrLen);40if (ret > 0)41 {42 recvData[ret] = 0x00;43 printf("接受到⼀个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));44 printf(recvData);45 }4647char * sendData = "⼀个来⾃服务端的UDP数据包\n";48 sendto(serSocket, sendData, strlen(sendData), 0, (sockaddr *)&remoteAddr, nAddrLen); 4950 }51 closesocket(serSocket);52 WSACleanup();53return0;54 }CLIENT 端1 #include "stdafx.h"2 #include <stdio.h>3 #include <winsock2.h>45#pragma comment(lib, "ws2_32.lib")67int main(int argc, char* argv[])8 {9 WORD socketVersion = MAKEWORD(2,2);10 WSADATA wsaData;11if(WSAStartup(socketVersion, &wsaData) != 0)12 {13return0;14 }15 SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);1617 sockaddr_in sin;18 sin.sin_family = AF_INET;19 sin.sin_port = htons(8888);20 sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");21int len = sizeof(sin);2223char * sendData = "来⾃客户端的数据包.\n";24 sendto(sclient, sendData, strlen(sendData), 0, (sockaddr *)&sin, len);2526char recvData[255];27int ret = recvfrom(sclient, recvData, 255, 0, (sockaddr *)&sin, &len);28if(ret > 0)29 {30 recvData[ret] = 0x00;31 printf(recvData);32 }3334 closesocket(sclient);35 WSACleanup();36return0;37 }本⽂来⾄:jpg 改 rar。

C语言之socket开发TCP、UDP通信总结

C语言之socket开发TCP、UDP通信总结

C语言之socket开发TCP、UDP通信总结一、什么是socket?Socket的英文原义是“孔”或“插座”。

在编程中,Socket被称做套接字,是网络通信中的一种约定。

Socket编程的应用无处不在,都与Socket 编程有关。

我们平时使用浏览器查资料,这个过程的技术原理是怎样的呢?我们平时使用浏览器,大致就是这样的一个过程。

这里有两个重要的名词:服务端与客户端。

Socket编程的目的就是如何实现这两端之间的通信。

1、Socket编程在嵌入式中也很重要Socket编程不仅仅在互联网方面很重要,在我们的嵌入式方面也是非常的重要,因为现在很多电子设备都趋向于联网。

比如很多嵌入式工作的招聘要求都会有这一条要求:二、Socket编程中的几个重要概念Socket编程用于解决我们客户端与服务端之间通信的问题。

我们平时多多少少都有听过IP地址、端口、TCP协议、UDP协议等概念,这些都与Socket编程中相关,想要知道怎么用起来,当然得先了解它们的一些介绍。

下面看一下这些专业术语的一些要点介绍:1、什么是IP地址?IP地址(InternetProtocolAddress)是指互联网协议地址,又译为网际协议地址。

IP地址被用来给Internet上的电脑一个编号。

我们可以把“个人电脑”比作“一台电话”,那么“IP地址”就相当于“电话号码”。

若计算机1知道计算机2的IP地址,则计算机1就能访问计算机2。

IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。

IP地址通常用点分十进制表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。

例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)。

IP地址有IPv4与IPv6之分,现在用得较多的是IPv4。

其中,有一个特殊的IP地址需要我们记住:127.0.0.1,这是回送地址,即本地机,一般用来测试使用。

windows socket编程c语言

windows socket编程c语言

windows socket编程c语言Windows Socket编程是一种用于在Windows操作系统上进行网络通信的编程技术。

通过使用Windows Socket API,开发人员可以使用C语言来创建网络应用程序,实现网络通信的各种功能。

Windows Socket编程的主要目标是建立和管理网络连接。

它提供了一套函数和数据结构,用于创建和管理套接字(Socket),这是网络通信的基本单元。

套接字可以用于在客户端和服务器之间传输数据,可以是TCP套接字,也可以是UDP套接字。

在Windows Socket编程中,首先需要创建一个套接字。

套接字可以通过调用socket函数来创建,该函数接受三个参数:地址族(AF_INET或AF_INET6),套接字类型(SOCK_STREAM或SOCK_DGRAM)和协议(通常为0)。

创建套接字后,可以使用bind函数将套接字绑定到特定的IP地址和端口号。

一旦套接字被创建和绑定,就可以使用connect函数在客户端和服务器之间建立连接。

对于TCP套接字,可以使用listen函数开始监听连接请求,并使用accept函数接受客户端的连接。

对于UDP套接字,不需要建立连接,可以直接发送和接收数据。

一旦连接建立成功,就可以使用send和recv函数在套接字之间传输数据。

send函数用于将数据发送到远程主机,而recv函数用于接收远程主机发送的数据。

可以使用这两个函数进行双向通信,发送和接收数据。

Windows Socket编程还提供了一些其他的函数和数据结构,用于处理网络通信中的其他问题。

例如,可以使用getaddrinfo函数解析主机名和服务名,以获取对应的IP地址和端口号。

可以使用select函数在多个套接字之间进行多路复用,以实现并发处理。

可以使用ioctlsocket函数设置套接字的属性,例如非阻塞模式。

除了基本的网络通信功能,Windows Socket编程还支持一些高级功能,例如多线程和异步操作。

socket编程c语言

socket编程c语言

socket编程c语言Socket编程是一种网络编程的方法,它通过使用TCP/IP协议栈,允许计算机上的不同进程之间进行通信。

在C语言中,我们可以使用socket库来实现这种网络编程。

Socket是一种抽象层,它提供了一种机制,可以将网络通信抽象为输入输出流。

通过Socket编程,我们可以建立网络连接,并通过网络发送和接收数据。

Socket编程主要涉及两种类型的Socket,即服务器Socket和客户端Socket。

服务器Socket用于监听并接受来自客户端的连接请求,而客户端Socket用于向服务器发送连接请求。

在C语言中,创建一个Socket可以通过调用socket()函数来实现。

这个函数接受三个参数:地址族(AF_INET表示使用IPv4地址)、套接字类型(SOCK_STREAM表示使用TCP协议)、以及协议类型(通常为0,表示让系统自动选择合适的协议)。

创建Socket后,我们可以通过调用bind()函数将Socket与一个特定的IP地址和端口号绑定在一起。

然后,调用listen()函数将Socket置于监听状态,等待客户端的连接请求。

如果有客户端发送连接请求,服务器Socket会接受这个请求,并返回一个新的Socket,用于与该客户端进行通信。

然后,服务器可以通过调用accept()函数来接受这个连接请求。

accept()函数会返回一个新的Socket,用于与客户端进行通信。

客户端Socket可以通过调用connect()函数与服务器建立连接。

这个函数接受服务器的IP地址和端口号作为参数。

如果连接成功,客户端Socket就可以像与服务器直接通信一样,发送和接收数据。

通过Socket编程,我们可以实现各种各样的网络应用。

例如,我们可以实现一个Web服务器,用于提供网页和处理HTTP请求。

我们也可以实现一个聊天程序,用于实时聊天。

此外,还可以通过Socket编程实现其他各种网络服务,如FTP、SMTP、POP3等。

Socket编程UDP_c语言版-可运行

Socket编程UDP_c语言版-可运行

//服务器端#include <Winsock2.h>#include <stdio.h>#define INV ALID_V ALUE32 0xFFFF#pragma comment(lib, "ws2_32.lib")void main(){int err = INV ALID_V ALUE32;WORD ver;WSADATA wsaData;//定义版本号ver = MAKEWORD(2, 2); /* 版本号为2.2版本,1.1也可以*//* 接下来初始化*/err = WSAStartup(ver, &wsaData);if (err != 0) /* 检查socket是否初始化成功*/{return;}if ((LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 2)){WSACleanup(); /* 版本错误则清楚导入的DLL */return;}/* 开始socket的主体部分:创建socket */SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); /* AF_INET表示网络使用的范围internetwork: UDP, TCP, etc,SOCK_STREAM表示使用的是TCPSOCK_DGRAM 表示使用的是UDP类型*/SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(7861); /* 端口随便只要不跟系统冲突就行*//* 下面开始绑定bind网卡*/bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); //绑定端口sockSrv要强制转换成SOCKADDR/* 定义几个缓冲区,也是接受和发送的,设置成100即可*/char recvbuf[100];char sendbuf[100];char tmpbuf[100];SOCKADDR_IN addrClient;// 连接上的客户端ip地址int len = sizeof(SOCKADDR);printf("\n************欢迎使用本软件*******\n");/* 下面进入死循环*/while (1){recvfrom(sockSrv, recvbuf, 100, 0, (SOCKADDR *)&addrClient, &len);if ('q' == recvbuf[0]){sendto(sockSrv, "q", strlen("q")+1, 0, (SOCKADDR *)&addrClient, len);printf("The chat is end!\n");break;}/* 将接收到的数据存入数据缓冲区,以便显示*/sprintf(tmpbuf,"%s say: %s ",inet_ntoa(addrClient.sin_addr), recvbuf);printf("%s\n", tmpbuf);printf("prease input:\n");gets(sendbuf);sendto(sockSrv, sendbuf, strlen(sendbuf)+1, 0, (SOCKADDR *)&addrClient, len);}/* 最后将socket清空*/closesocket(sockSrv);WSACleanup();return;}//客户端#include <Winsock2.h>#include <stdio.h>#define INV ALID_V ALUE32 0xFFFF#pragma comment(lib, "ws2_32.lib")//客户端主函数开始void main(){int err = INV ALID_V ALUE32;WORD ver;WSADATA wsaData;//定义版本号ver = MAKEWORD(2, 2); /* 版本号为2.2版本,1.1也可以*//* 接下来初始化*/err = WSAStartup(ver, &wsaData);if (err != 0) /* 检查socket是否初始化成功*/{return;}if (2 != (LOBYTE(wsaData.wVersion)) || (2 != HIBYTE(wsaData.wVersion))){WSACleanup(); /* 版本错误则清楚导入的DLL */return;}/* 开始socket的主体部分:创建socket */SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0); /* AF_INET表示网络使用的范围internetwork: UDP, TCP, etc,SOCK_STREAM表示使用的是TCPSOCK_DGRAM 表示使用的是UDP类型*/SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 这里设置为服务器的IP地址,由于我在自己的机器上面写的,所以写回环地址了addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(7861); /* 端口随便只要不跟系统冲突就行*//* 定义几个缓冲区,也是接受和发送的,设置成100即可*/char recvbuf[100];char sendbuf[100];int len=sizeof(SOCKADDR);printf("\n************欢迎使用本软件*******\n");/* 下面进入死循环*/while (1){printf("\n请输入内容:\n");gets(sendbuf);sendto(sockClient, sendbuf, strlen(sendbuf)+1, 0, (SOCKADDR *)&addrSrv, len);recvfrom(sockClient, recvbuf, 100, 0, (SOCKADDR *)&addrSrv, &len);if ('q' == recvbuf[0]){sendto(sockClient, "q", strlen("q")+1, 0, (SOCKADDR *)&addrSrv, len);printf("The chat is end!\n");break;}/* 将接收到的数据存入数据缓冲区,以便显示*/printf("%s say: %s", inet_ntoa(addrSrv.sin_addr), recvbuf);}/* 最后将socket清空*/closesocket(sockClient);WSACleanup();return;}。

c socket 编程

c socket 编程

c socket 编程C语言中使用Socket编程可以实现网络通信,主要针对TCP和UDP两种协议。

下面是C Socket编程的相关参考内容。

1. 应用层通信模型:- 客户端/服务器模型:客户端向服务器发送请求,服务器接收请求并发送回复。

- 对等通信模型:两个或多个进程之间直接通信,不需要中间服务器。

2. Socket编程流程:- 创建Socket:使用`socket()`函数创建一个Socket。

- 绑定Socket:使用`bind()`函数将Socket绑定到一个特定的地址和端口号。

- 监听连接请求:对于服务器端,使用`listen()`函数监听连接请求。

- 接收连接请求:对于服务器端,使用`accept()`函数接收连接请求。

- 建立连接:对于客户端,使用`connect()`函数连接到服务器。

- 发送和接收数据:使用`send()`和`recv()`函数发送和接收数据。

- 关闭连接:使用`close()`函数关闭Socket连接。

3. TCP Socket编程:- 创建Socket:使用`socket(AF_INET, SOCK_STREAM, 0)`函数创建TCP Socket。

- 绑定Socket:使用`bind()`函数将Socket绑定到服务器的地址和端口号。

- 监听连接请求:使用`listen()`函数开始监听连接请求。

- 接收连接请求:使用`accept()`函数接收来自客户端的连接请求,并创建一个新的Socket用于通信。

- 建立连接:使用`connect()`函数连接到服务器的地址和端口号。

- 发送和接收数据:使用`send()`和`recv()`函数发送和接收数据。

- 关闭连接:使用`close()`函数关闭Socket连接。

4. UDP Socket编程:- 创建Socket:使用`socket(AF_INET, SOCK_DGRAM, 0)`函数创建UDP Socket。

C语言实现UDP网络传输

C语言实现UDP网络传输

C语言实现UDP网络传输UDP(User Datagram Protocol,用户数据报协议)是一种面向无连接的传输协议,它在网络编程中具有重要的作用。

本文将介绍C语言如何实现UDP网络传输的基本原理和步骤。

一、UDP网络传输简介UDP是一种简单的传输层协议,相对于TCP(Transmission Control Protocol,传输控制协议)来说,UDP更加轻量级。

它不提供可靠性和流量控制,但是具有实时性较高的特点,适用于需要快速传输数据的场景,如音频、视频等实时应用。

UDP协议的数据包格式主要包括源端口号、目标端口号、长度、校验和以及数据。

由于UDP是无连接的,所以每个数据包都是独立发送的,不需要建立和维护连接,这使得UDP的实现相对简单。

二、C语言实现UDP网络传输步骤要使用C语言实现UDP网络传输,我们需要按照以下步骤进行操作:1. 创建套接字(Socket)在C语言中,使用socket()函数创建一个套接字,该套接字用于后续的数据传输。

在创建套接字时,需要指定协议簇(AF_INET代表IPv4)和套接字类型(SOCK_DGRAM代表使用UDP协议)。

2. 绑定本地地址和端口号使用bind()函数将套接字与本地地址和端口号绑定,以便接收数据和发送数据。

通常将本地地址设置为INADDR_ANY,端口号可以自定义。

3. 接收数据使用recvfrom()函数接收远程主机发送的数据,该函数会将接收到的数据存储到指定的缓冲区中,并返回接收到的字节数。

可以通过指定发送方的地址和端口号来实现数据的精确接收。

4. 发送数据使用sendto()函数将数据发送给目标主机,该函数需要指定目标主机的地址和端口号,并将待发送的数据和数据长度作为参数传入。

5. 关闭套接字使用close()函数关闭套接字,释放资源。

三、C语言实现UDP网络传输示例代码```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <arpa/inet.h>#define MAX_BUFFER_SIZE 1024#define SERVER_PORT 8888#define SERVER_IP "127.0.0.1"int main() {int sockfd;char buffer[MAX_BUFFER_SIZE];struct sockaddr_in server_addr, client_addr;socklen_t client_len = sizeof(client_addr);// 创建套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("Error in creating socket");exit(1);}memset(&server_addr, 0, sizeof(server_addr));memset(&client_addr, 0, sizeof(client_addr));// 设置服务器地址和端口号server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);// 绑定本地地址和端口号if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("Error in binding");exit(1);}printf("Server is listening for incoming connections...\n");while (1) {// 接收数据memset(buffer, 0, sizeof(buffer));ssize_t recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);if (recv_len < 0) {perror("Error in receiving data");exit(1);}printf("Received data from client: %s\n", buffer);// 发送数据const char* msg = "Hello, client!";ssize_t send_len = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&client_addr, client_len);if (send_len != strlen(msg)) {perror("Error in sending data");exit(1);}printf("Sent response to client: %s\n", msg);}// 关闭套接字close(sockfd);return 0;}```以上是一个简单的UDP服务器示例代码,它通过创建套接字、绑定地址和端口、接收数据并发送响应的方式来实现UDP网络传输。

hpsocket c语言例子

hpsocket c语言例子

hpsocket c语言例子HP-Socket是一个基于IOCP(IO Completion Port)的高性能网络通信框架,提供了TCP和UDP的客户端和服务器端实现,支持IPv4和IPv6,适用于Windows操作系统。

下面将列举10个HP-Socket C语言例子,以便更好地理解和使用该框架。

1. 简单的TCP服务器和客户端示例这个例子演示了如何使用HP-Socket框架创建一个简单的TCP服务器和客户端,服务器接收客户端的连接和数据,并将其原样返回给客户端。

2. 异步TCP服务器和客户端示例这个例子展示了如何使用HP-Socket框架创建一个异步的TCP服务器和客户端,服务器和客户端之间的通信是非阻塞的,提高了系统的并发处理能力。

3. UDP服务器和客户端示例这个例子展示了如何使用HP-Socket框架创建一个UDP服务器和客户端,服务器接收客户端发送的数据包,并将其原样返回给客户端。

4. 大文件传输示例这个例子演示了如何使用HP-Socket框架实现大文件的传输,通过分片传输和MD5校验,确保文件传输的可靠性和完整性。

5. SSL加密通信示例这个例子演示了如何使用HP-Socket框架实现SSL加密通信,保护数据在网络传输过程中的安全性。

6. 自定义协议示例这个例子展示了如何使用HP-Socket框架实现自定义协议的通信,通过自定义协议头部和数据格式,实现更灵活的数据交互。

7. 多线程服务器示例这个例子演示了如何使用多线程来处理客户端的连接和数据,提高服务器的并发处理能力。

8. 定时器示例这个例子展示了如何使用HP-Socket框架实现定时器功能,定时执行某些操作,例如定时发送心跳包。

9. 数据压缩和解压缩示例这个例子展示了如何使用HP-Socket框架实现数据的压缩和解压缩,减少数据在网络传输中的带宽占用。

10. 代理服务器示例这个例子演示了如何使用HP-Socket框架实现代理服务器,实现客户端和目标服务器之间的数据转发。

多线程程序c语言

多线程程序c语言

多线程程序c语言多线程是计算机中的一个概念,它可以让多个线程同步运行,从而加快计算机运行速度,改善性能。

而在C语言中,使用多线程的方法也是被广泛应用于各个领域中的。

本文将为大家详细讲解如何在C语言中创建和管理多线程。

一、线程和进程的概念在C语言中,线程是执行代码的一种方式,它可以用来实现并发和异步编程。

而进程是资源分配的最小单位,每个进程都有自己的地址空间和独立的工作流程。

一个进程可以包含多个线程。

在操作系统的层面,每个线程都是由进程来管理的,由于线程共享进程的地址空间,所以它们之间的数据传递和通信比较方便。

二、多线程的实现方法在C语言中,要实现多线程的功能,需要使用相关的函数库。

其中最常用的函数库是pthread,使用它可以轻松地创建和管理多个线程。

1. 线程的创建线程的创建主要是通过pthread_create函数实现的。

它的原型定义如下:```#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg);```该函数的第一个参数是一个指向线程ID的指针,第二个参数是指向线程属性的指针,第三个参数是线程所要执行的函数,最后一个参数是传递给函数的参数。

调用成功后,会返回0,并将线程ID放到第一个参数所指向的地址中。

```#include <pthread.h>int pthread_cancel(pthread_t thread);```该函数的参数是要撤销的线程ID。

调用成功后,函数会直接将指定的线程终止掉,并释放它所占用的资源。

三、多线程的应用场景在C语言中,多线程的应用场景非常广泛,下面分别介绍几种典型的应用场景:1. 网络编程在网络编程中,要同时处理多个客户端请求,这时使用多线程可以使程序并发执行,效率更高。

VC中网络编程的常用函数及UDP,TCP协议编程步骤

VC中网络编程的常用函数及UDP,TCP协议编程步骤

VC中网络编程的常用函数及UDP,TCP协议编程步骤编写:<单击输入编写人>1.SOCKET类型SOCKET是socket套接字类型,在WINSOCK2.H中有如下定义:typedef unsigned int u_int;typedef u_int SOCKET;可知套接字实际上就是一个无符号整型,它将被Socket环境管理和使用。

套接字将被创建、设置、用来发送和接收数据,最后会被关闭。

2.WORD类型、MAKEWORD、LOBYTE和HIBYTE宏WORD类型是一个16位的无符号整型,在WTYPES.H中被定义为:typedef unsigned short WORD;其目的是提供两个字节的存储,在Socket中这两个字节可以表示主版本号和副版本号。

使用MAKEWORD宏可以给一个WORD类型赋值。

例如要表示主版本号2,副版本号0,可以使用以下代码:WORD wVersionRequested; wVersionRequested = MAKEWORD( 2, 0 );注意低位内存存储主版本号2,高位内存存储副版本号0,其值为0x0002。

使用宏LOBYTE可以读取WORD的低位字节,HIBYTE可以读取高位字节。

3. WSADATA类型和LPWSADATA类型WSADATA类型是一个结构,描述了Socket库的一些相关信息,其结构定义如下:typedef struct WSAData {WORD wVersion;WORD wHighVersion;char szDescription[WSADESCRIPTION_LEN+1];char szSystemStatus[WSASYS_STATUS_LEN+1];unsigned short iMaxSockets;unsigned short iMaxUdpDg;char FAR * lpVendorInfo;} WSADATA;typedef WSADATA FAR *LPWSADATA;值得注意的就是wVersion字段,存储了Socket的版本类型。

socket多人聊天程序C语言版解析

socket多人聊天程序C语言版解析

socket多人聊天程序C语言版1V1实现了,1V多也就容易了。

不过相对于1V1的程序,我经过大改,采用链表来动态管理。

这样效率真的提升不少,至少CPU使用率稳稳的在20以下,不会飙到100了。

用C语言写这个还是挺费时间的,因为什么功能函数都要自己写,不像C++有STL库可以用,MFC 写就更简单了,接下来我还会更新MFC版本的多人聊天程序。

好了,废话少说,进入主题。

这个程序要解决的问题如下:1.CPU使用率飙升问题–>用链表动态管理2.用户自定义聊天,就是想跟谁聊跟谁聊–> _Client结构体中新增一个ChatName字段,用来表示要和谁聊天,这个字段很重要,因为server转发消息的时候就是按照这个字段来转发的。

3.中途换人聊天,就是聊着聊着,想和别人聊,而且自己还一样能接收到其它人发的消息–> 这个就要小改客户端的代码了,可以在发送聊天消息之前插入一段代码,用来切换聊天用户。

具体做法就是,用getch()函数读取ESC键,如果用户按了这个键,则表示想切换用户,然后会输出一行提示,请输入chat name,就是想要和谁聊天的名字,发送这个名字过去之前要加一个标识符,表示这个消息是切换聊天用户消息。

然后server接收到这个消息后会判断第一个字符是不是标识符,第二个字符不能是标识符,则根据这个name来查找当前在线的用户,然后修改想切换聊天用户的ChatName为name这个用户。

(可能有点绕,不懂的看代码就清晰易懂了~)4.下线后提醒对方–> 还是老套路,只要send对方不通就当对方下线了。

编写环境:WIN10,VS2015效果图:为了方便就不用虚拟机演示了,但是在虚拟机是肯定可以的,应该说只要是局域网,能互相ping通就可以使用这个程序。

Server code:链表头文件:#ifndef _CLIENT_LINK_LIST_H_#define _CLIENT_LINK_LIST_H_#include <winsock2.h>#include <stdio.h>//客户端信息结构体typedef struct _Client{SOCKET sClient; //客户端套接字char buf[128]; //数据缓冲区char userName[16]; //客户端用户名char IP[20]; //客户端IPunsigned short Port; //客户端端口UINT_PTR flag; //标记客户端,用来区分不同的客户端char ChatName[16]; //指定要和哪个客户端聊天_Client* next; //指向下一个结点}Client, *pClient;/** function 初始化链表* return 无返回值*/void Init();/** function 获取头节点* return 返回头节点*/pClient GetHeadNode();/** function 添加一个客户端* param client表示一个客户端对象* return 无返回值*/void AddClient(pClient client);/** function 删除一个客户端* param flag标识一个客户端对象* return 返回true表示删除成功,false表示失败*/bool RemoveClient(UINT_PTR flag);/** function 根据name查找指定客户端* param name是指定客户端的用户名* return 返回一个client表示查找成功,返回INVALID_SOCKET表示无此用户*/SOCKET FindClient(char* name);/** function 根据SOCKET查找指定客户端* param client是指定客户端的套接字* return 返回一个pClient表示查找成功,返回NULL表示无此用户*/pClient FindClient(SOCKET client);/** function 计算客户端连接数* param client表示一个客户端对象* return 返回连接数*/int CountCon();/** function 清空链表* return 无返回值*/void ClearClient();/** function 检查连接状态并关闭一个连接* return 返回值*/void CheckConnection();/** function 指定发送给哪个客户端* param FromName,发信人* param ToName, 收信人* param data, 发送的消息*/void SendData(char* FromName, char* ToName, char* data);#endif //_CLIENT_LINK_LIST_H_</stdio.h></winsock2.h>链表cpp文件:?#include "ClientLinkList.h"pClient head = (pClient)malloc(sizeof(_Client)); //创建一个头结点/** function 初始化链表* return 无返回值*/{head->next = NULL;}/** function 获取头节点* return 返回头节点*/pClient GetHeadNode(){return head;}/** function 添加一个客户端* param client表示一个客户端对象* return 无返回值*/void AddClient(pClient client){client->next = head->next; //比如:head->1->2,然后添加一个3进来后是head->next = client; //3->1->2,head->3->1->2}/** function 删除一个客户端* param flag标识一个客户端对象* return 返回true表示删除成功,false表示失败*/bool RemoveClient(UINT_PTR flag){//从头遍历,一个个比较pClient pCur = head->next;//pCur指向第一个结点pClient pPre = head; //pPre指向headwhile (pCur){// head->1->2->3->4,要删除2,则直接让1->3if (pCur->flag == flag){pPre->next = pCur->next;closesocket(pCur->sClient); //关闭套接字free(pCur); //释放该结点return true;pPre = pCur;pCur = pCur->next;}return false;}/** function 查找指定客户端* param name是指定客户端的用户名* return 返回socket表示查找成功,返回INVALID_SOCKET表示无此用户*/SOCKET FindClient(char* name){//从头遍历,一个个比较pClient pCur = head;while (pCur = pCur->next){if (strcmp(pCur->userName, name) == 0)return pCur->sClient;}return INVALID_SOCKET;}/** function 根据SOCKET查找指定客户端* param client是指定客户端的套接字* return 返回一个pClient表示查找成功,返回NULL表示无此用户*/pClient FindClient(SOCKET client){//从头遍历,一个个比较pClient pCur = head;while (pCur = pCur->next){if (pCur->sClient == client)return pCur;}return NULL;}/** function 计算客户端连接数* param client表示一个客户端对象* return 返回连接数*/int CountCon(){int iCount = 0;pClient pCur = head;while (pCur = pCur->next)iCount++;return iCount;}/** function 清空链表* return 无返回值*/void ClearClient(){pClient pCur = head->next;pClient pPre = head;while (pCur){//head->1->2->3->4,先删除1,head->2,然后free 1pClient p = pCur;pPre->next = p->next;free(p);pCur = pPre->next;}}/** function 检查连接状态并关闭一个连接* return 返回值*/void CheckConnection(){pClient pclient = GetHeadNode();while (pclient = pclient->next){if (send(pclient->sClient, "", sizeof(""), 0) == SOCKET_ERROR){if (pclient->sClient != 0){printf("Disconnect from IP: %s,UserName: %s\n", pclient->IP, pclient->userName);char error[128] = { 0 }; //发送下线消息给发消息的人sprintf(error, "The %s was downline.\n", pclient->userName);send(FindClient(pclient->ChatName), error, sizeof(error), 0);closesocket(pclient->sClient); //这里简单的判断:若发送消息失败,则认为连接中断(其原因有多种),关闭该套接字RemoveClient(pclient->flag);break;}}}}/** function 指定发送给哪个客户端* param FromName,发信人* param ToName, 收信人* param data, 发送的消息*/void SendData(char* FromName, char* ToName, char* data){SOCKET client = FindClient(ToName); //查找是否有此用户char error[128] = { 0 };int ret = 0;if (client != INVALID_SOCKET && strlen(data) != 0){char buf[128] = { 0 };sprintf(buf, "%s: %s", FromName, data); //添加发送消息的用户名ret = send(client, buf, sizeof(buf), 0);}else//发送错误消息给发消息的人{if(client == INVALID_SOCKET)sprintf(error, "The %s was downline.\n", ToName);elsesprintf(error, "Send to %s message not allow empty, Please try again!\n", ToName);send(FindClient(FromName), error, sizeof(error), 0);}if (ret == SOCKET_ERROR)//发送下线消息给发消息的人{sprintf(error, "The %s was downline.\n", ToName);send(FindClient(FromName), error, sizeof(error), 0);}}server cpp:?/*#include <winsock2.h>#include <process.h>#include <stdlib.h>#include "ClientLinkList.h"#pragma comment(lib,"ws2_32.lib")SOCKET g_ServerSocket = INVALID_SOCKET; //服务端套接字SOCKADDR_IN g_ClientAddr = { 0 }; //客户端地址int g_iClientAddrLen = sizeof(g_ClientAddr);typedef struct _Send{char FromName[16];char ToName[16];char data[128];}Send,*pSend;//发送数据线程unsigned __stdcall ThreadSend(void* param){pSend psend = (pSend)param; //转换为Send类型SendData(psend->FromName, psend->ToName, psend->data); //发送数据return 0;}//接受数据unsigned __stdcall ThreadRecv(void* param){int ret = 0;while (1){pClient pclient = (pClient)param;if (!pclient)return 1;ret = recv(pclient->sClient, pclient->buf, sizeof(pclient->buf), 0);if (ret == SOCKET_ERROR)return 1;if (pclient->buf[0] == '#' && pclient->buf[1] != '#') //#表示用户要指定另一个用户进行聊天{SOCKET socket = FindClient(&pclient->buf[1]); //验证一下客户是否存在if (socket != INVALID_SOCKET){pClient c = (pClient)malloc(sizeof(_Client));c = FindClient(socket); //只要改变ChatName,发送消息的时候就会自动发给指定的用户了memset(pclient->ChatName, 0, sizeof(pclient->ChatName));memcpy(pclient->ChatName , c->userName,sizeof(pclient->ChatName));}elsesend(pclient->sClient, "The user have not online or not exits.",64,0);continue;}pSend psend = (pSend)malloc(sizeof(_Send));//把发送人的用户名和接收消息的用户和消息赋值给结构体,然后当作参数传进发送消息进程中memcpy(psend->FromName, pclient->userName, sizeof(psend->FromName));memcpy(psend->ToName, pclient->ChatName, sizeof(psend->ToName));memcpy(psend->data, ->buf, sizeof(psend->data));_beginthreadex(NULL, 0, ThreadSend, psend, 0, NULL);Sleep(200);}return 0;}//开启接收消息线程void StartRecv(){pClient pclient = GetHeadNode();while (pclient = pclient->next)_beginthreadex(NULL, 0, ThreadRecv, pclient, 0, NULL);}//管理连接unsigned __stdcall ThreadManager(void* param){while (1){CheckConnection(); //检查连接状况Sleep(2000); //2s检查一次}return 0;}//接受请求unsigned __stdcall ThreadAccept(void* param){_beginthreadex(NULL, 0, ThreadManager, NULL, 0, NULL);Init(); //初始化一定不要再while里面做,否则head会一直为NULL!!!while (1){//创建一个新的客户端对象pClient pclient = (pClient)malloc(sizeof(_Client));//如果有客户端申请连接就接受连接if ((pclient->sClient = accept(g_ServerSocket, (SOCKADDR*)&g_ClientAddr, &g_iClientAddrLen)) == INVALID_SOCKET){printf("accept failed with error code: %d\n", WSAGetLastError());closesocket(g_ServerSocket);WSACleanup();return -1;}recv(pclient->sClient, pclient->userName, sizeof(pclient->userName), 0); //接收用户名和指定聊天对象的用户名recv(pclient->sClient, pclient->ChatName, sizeof(pclient->ChatName), 0);memcpy(pclient->IP, inet_ntoa(g_ClientAddr.sin_addr), sizeof(pclient->IP)); //记录客户端IPpclient->flag = pclient->sClient; //不同的socke有不同UINT_PTR类型的数字来标识pclient->Port = htons(g_ClientAddr.sin_port);AddClient(pclient); //把新的客户端加入链表中printf("Successfuuly got a connection from IP:%s ,Port: %d,UerName: %s , ChatName: %s\n",pclient->IP, pclient->Port, pclient->userName,pclient->ChatName);if (CountCon() >= 2) //当至少两个用户都连接上服务器后才进行消息转发StartRecv();Sleep(2000);}return 0;}//启动服务器int StartServer(){//存放套接字信息的结构WSADATA wsaData = { 0 };SOCKADDR_IN ServerAddr = { 0 }; //服务端地址USHORT uPort = 18000; //服务器监听端口//初始化套接字if (WSAStartup(MAKEWORD(2, 2), &wsaData)){printf("WSAStartup failed with error code: %d\n", WSAGetLastError());return -1;}//判断版本if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){printf("wVersion was not 2.2\n");return -1;}//创建套接字g_ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (g_ServerSocket == INVALID_SOCKET){printf("socket failed with error code: %d\n", WSAGetLastError());return -1;}//设置服务器地址ServerAddr.sin_family = AF_INET;//连接方式ServerAddr.sin_port = htons(uPort);//服务器监听端口ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//任何客户端都能连接这个服务器//绑定服务器if (SOCKET_ERROR == bind(g_ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))){printf("bind failed with error code: %d\n", WSAGetLastError());closesocket(g_ServerSocket);return -1;}//设置监听客户端连接数if (SOCKET_ERROR == listen(g_ServerSocket, 20000)){printf("listen failed with error code: %d\n", WSAGetLastError());closesocket(g_ServerSocket);WSACleanup();return -1;}_beginthreadex(NULL, 0, ThreadAccept, NULL, 0, 0);for (int k = 0;k < 100;k++) //让主线程休眠,不让它关闭TCP连接.Sleep(10000000);//关闭套接字ClearClient();closesocket(g_ServerSocket);WSACleanup();return 0;}int main(){StartServer(); //启动服务器return 0;}</stdlib.h></process.h></winsock2.h>Client code:?#define _WINSOCK_DEPRECATED_NO_WARNINGS#include <winsock2.h>#include <process.h>#include <stdio.h>#include <stdlib.h>#include <conio.h>#pragma comment(lib,"ws2_32.lib")#define RECV_OVER 1#define RECV_YET 0char userName[16] = { 0 };char chatName[16] = { 0 };int iStatus = RECV_YET;//接受数据unsigned __stdcall ThreadRecv(void* param){char buf[128] = { 0 };while (1){int ret = recv(*(SOCKET*)param, buf, sizeof(buf), 0);if (ret == SOCKET_ERROR){Sleep(500);continue;}if (strlen(buf) != 0){printf("%s\n", buf);iStatus = RECV_OVER;}elseSleep(100);}return 0;}//发送数据unsigned __stdcall ThreadSend(void* param){char buf[128] = { 0 };int ret = 0;while (1){int c = getch();if (c == 27) //ESC ASCII是27{memset(buf, 0, sizeof(buf));printf("Please input the chat name:");gets_s(buf);char b[17] = { 0 };sprintf(b, "#%s", buf);ret = send(*(SOCKET*)param,b , sizeof(b), 0);if (ret == SOCKET_ERROR)return 1;continue;}if(c == 72 || c == 0 || c == 68)//为了显示美观,加一个无回显的读取字符函数continue; //getch返回值我是经过实验得出如果是返回这几个值,则getch就会自动跳过,具体我也不懂。

socket多人聊天程序C语言版(一)

socket多人聊天程序C语言版(一)

socket多⼈聊天程序C语⾔版(⼀)本⽂实例为⼤家分享了C语⾔实现socket多⼈聊天程序的第⼀篇,供⼤家参考,具体内容如下⾸先,不要⼀步登天直接解决多⼈聊天这个问题,先把问题化简。

1.多⼈聊天的核⼼问题是服务器如何标识不同的客户端,如何根据客户端的需求转发消息给指定客户端。

2.多⼈聊天转化为C-C聊天,但是不再是直接C-C,⽽是通过server转发消息,所以变成==>C-S-C。

3.server如何允许2个client同时连接,设置listen函数的第⼆个参数,最⼤连接数。

4.server如何标识两个client,⽤⼀个结构体数组来存放两个client的信息。

5.server如何转发消息给client,很简单,先接收到的发送给还没接收到的。

如图:6.server如何管理两个client的连接状态,连接成功很简单,就是accpet成功后就是连接成功了。

但是怎么判断连接断开呢?这个涉及到的select函数的使⽤,有点复杂~,所以我就简单的⽤了⼀个send函数发送⼀个空消息来判断是否断开连接,这个不严谨,容易出BUG,但是实践起来简单就使⽤了它。

7.要⽤线程来管理接收消息、发送消息、接受请求、管理连接状态。

技术要点:C语⾔线程函数的使⽤。

_beginthreadex函数原型_ACRTIMP uintptr_t __cdecl _beginthreadex( _In_opt_ void* _Security,//安全属性,NULL为默认安全属性_In_ unsigned _StackSize,//线程堆栈的⼤⼩。

如果为0,则线程堆栈⼤⼩和创建它的线程的相同。

⼀般⽤0_In_ _beginthreadex_proc_type _StartAddress, //线程函数的地址_In_opt_ void* _ArgList, //传进线程的函数_In_ unsigned _InitFlag, //线程初始状态,0:⽴即运⾏;CREATE_SUSPEND:悬挂(如果出事状态定义为悬挂,就要调⽤ResumeThread(HANDLE) 来激活线程的运⾏) _Out_opt_ unsigned* _ThrdAddr //⽤于记录线程ID的地址)例⼦:#include <process.h>#include <stdio.h>unsigned __stdcall Thread(void* param){printf("%d\n", *(int*)param); //这⾥必须先要强⾏转换为int*,不然void* 直接解引⽤会出错。

用 C 实现多线程 Socket 的通信

用 C 实现多线程 Socket 的通信

用 C 实现多线程 Socket 的通信Socket 是一种基于 IP 协议的网络协议,它提供网络连接和数据传输服务。

在多线程编程中,可以使用 Socket 实现线程之间的通信。

本文将介绍如何用 C 语言实现多线程 Socket 的通信。

首先,需要引入以下头文件:```#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <pthread.h>```其中,pthread.h 提供了用于多线程编程的函数和数据类型。

下面是一个简单的 Server 实现代码:```cvoid *server_thread(void *arg) {int server_fd, new_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};char *message = "Hello from server";int port = *(int*)arg;// 创建 Socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket failed");exit(EXIT_FAILURE);}// 设置 Socket 选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(port);// 绑定 Socket 到端口号if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 监听来自客户端的连接请求if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}// 接受客户端连接if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// 发送消息给客户端send(new_socket, message, strlen(message), 0);printf("Message sent to client\n");// 接收来自客户端的消息read(new_socket, buffer, 1024);printf("Message from client: %s\n", buffer);close(new_socket);close(server_fd);return NULL;}```上述代码中,server_thread 函数是一个 pthread_create 函数即可创建一个新的线程执行该函数:```cint main() {int port = 8080;pthread_t t_id;if (pthread_create(&t_id, NULL, server_thread, &port) != 0) { perror("pthread_create failed");exit(EXIT_FAILURE);}// 等待子线程结束pthread_join(t_id, NULL);return 0;}```当客户端连接到 Server 后,Server 发送一条消息给客户端,然后等待客户端发送消息过来。

解析C语言基于UDP协议进行Socket编程的要点

解析C语言基于UDP协议进行Socket编程的要点

解析C语⾔基于UDP协议进⾏Socket编程的要点两种协议 TCP 和 UDP前者可以理解为有保证的连接,后者是追求快速的连接。

当然最后⼀点有些太过绝对,但是现在不需熬考虑太多,因为初⼊套接字编程,⼀切从简。

稍微试想便能够⼤致理解, TCP 追求的是可靠的传输数据, UDP 追求的则是快速的传输数据。

前者有繁琐的连接过程,后者则是根本不建⽴可靠连接(不是绝对),只是将数据发送⽽不考虑是否到达。

以下例⼦以 *nix 平台的便准为例,因为 Windows平台需要考虑额外的加载问题,稍作添加就能在 Windows 平台上运⾏UDP。

UDP这是⼀个⼗分简洁的连接⽅式,假设有两台主机进⾏通信,⼀台只发送,⼀台只接收。

接收端:int sock; /* 套接字 */socklen_t addr_len; /* 发送端的地址长度,⽤于 recvfrom */char mess[15];char get_mess[GET_MAX]; /* 后续版本使⽤ */struct sockaddr_in recv_host, send_host;/* 创建套接字 */sock = socket(PF_INET, SOCK_DGRAM, 0);/* 把IP 和端⼝号信息绑定在套接字上 */memset(&recv_host, 0, sizeof(recv_host));recv_host.sin_family = AF_INET;recv_host.sin_addr.s_addr = htonl(INADDR_ANY);/* 接收任意的IP */recv_host.sin_port = htons(6000); /* 使⽤6000 端⼝号 */bind(sock, (struct sockaddr *)&recv_host, sizeof(recv_host));/* 进⼊接收信息的状态 */recvfrom(sock, mess, 15, 0, (struct sockaddr *)&send_host, &addr_len);/* 接收完成,关闭套接字 */close(sock);上述代码省略了许多必要的错误检查,在实际编写时要添加代码解释:PF_INET 代表协议的类型,此处代表 IPv4 ⽹络协议族,同样 PF_INET6 代表 IPv6 ⽹络协议族,这个范围在后⽅单独记录,不与IPv4混在⼀起(并不意味着更复杂,实际上更简便)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

char recvBuf[50]="\0";
int len=sizeof(SOCKADDR);
sockaddr_in addrClient;
while(1)
{
recvfrom(s,recvBuf,50,0,(SOCKADDR*)&addrClient,&len);
printf("他:\n %s\n",recvBuf);
#include <Winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI ThreadProc(LPVOID lpParameter) //次线程,发消息
tcpaddr2.sin_family=AF_INET;
tcpaddr2.sin_port=htons(5050); //发送端口5050
tcpaddr2.sin_addr.S_un.S_addr=inet_addr(ip);
int len=sizeof(SOCKADDR);
while(1)
{
printf("请输入服务端ip地址:");//程序接收端
char ip[16]="\0";
scanf("%s",ip);
//创建socket2
SOCKET s2=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
//创建套接口
sockaddr_in tcpaddr2;
Sleep(1000);
}
closesocket(s);
WSACleanup();
return 0;
}
{
printf("我:\n ");
char sendBuf[100]="\0";
scanf("%s",sendBuf);
sendto(s2,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&tcpaddr2,len);
Sleep(1000);
system("pause");
}
if(wsaData.wVersion!=wVersionRequested)
{
printf("Winsock 版本不匹配!\n");//Winsock版本不匹配
WSACleanup();
system("pause");
}
//创建socket
}
closesocket(s2);
return 0;
}
int main(int argc, char* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int iSockErr,iSockErr2;
int err;
wVersionRequested=MAKEWORD(2,2);
err = WSAStartup( wVersionRequested, &wsaData );
ቤተ መጻሕፍቲ ባይዱ
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
printf("Winsock 初始化错误!\n");//Winsock初始化错误
printf("%d",iSockErr);//根据不同的错误类型进行不同的处理
system("pause");
}
//进入多线程,发信息
HANDLE hThread;
hThread=CreateThread(NULL,0,ThreadProc,NULL,0,NULL);
CloseHandle(hThread);
SOCKET s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
//创建套接口
sockaddr_in tcpaddr;
tcpaddr.sin_family=AF_INET;
tcpaddr.sin_port=htons(5050); //接收端口5050
tcpaddr.sin_addr.s_addr=htonl(INADDR_ANY);
//绑定套接口
if(bind(s,(LPSOCKADDR)&tcpaddr,sizeof(tcpaddr))==SOCKET_ERROR)
{
iSockErr=WSAGetLastError();
相关文档
最新文档