server 端
#include <WINSOCK2.H>
#include <stdio.h>
#define PORT 6000 //服务器端口
#define MSGSIZE 1024 //收发缓冲区的大小
#pragma comment(lib, "ws2_32.lib") //链接静态库
DWORD WINAPI FunThread(LPVOID); //创建一个线程,专门用来接收数据
SOCKET sClient; //连接所用套节字
SOCKET sListen; //监听套接字
SOCKADDR_IN client; //保存客户的地址信息
int iaddrSize = sizeof(SOCKADDR_IN);
int main()
{
WSADATA wsaData;
SOCKADDR_IN local;
char s_Message[MSGSIZE]; //收发缓冲区
WSAStartup(0x0202, &wsaData); //Initialize Windows socket library
/*socket函数用于创建一个套接字*/
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建服务器监听套节字。TCP协议
/* bind函数用于将套接字绑定到一个已知的地址上。如果函数执行成功,返回值为0,否则为SOCKET_ERROR。*****/
local.sin_family = AF_INET; //AF_INET指明使用TCP/IP协议族
local.sin_port = htons(PORT); //指明连接服务器的端口号
local.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取本机地址
bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN)); //地址绑定到套接字
/*listen函数用于将套接字置入监听模式*/
listen(sListen, 1); //开始监听
/*accpet函数用于接受客户端的连接请求。返回值是一个新的套接字,它对应于已经接受的客户端连接,对于该客户端的所有后续操作,都应使用这个新的套接字*/
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize); //建立连接
printf("Accepte client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
HANDLE hThread=CreateThread(NULL,0,FunThread,0,0,0); //创建接收线程
CloseHandle(hThread); //关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等
while (TRUE)
{
printf("Server Send:"); //从键盘输入
gets(s_Message); //发送数据
/*send函数在已经建立连接的套接字上发送数据。*/
send(sClient, s_Message, strlen(s_Message), 0);
}
return 0;
}
/*程序中专门建立一个FunThread线程用来接收数据,实现双向通信,也可以连续发送、连续接收。*/
DWORD WINAPI FunThread(LPVOID)
{
char c_Message[MSGSIZE]; //收发缓冲区
int ret; //接收字节的个数
while (TRUE)
{
/*recv函数用于从连接的套接字中接收数据。*/
ret = recv(sClient, c_Message, MSGSIZE, 0); //接收数据
if(ret==SOCKET_ERROR)
{
printf("\nclient is closed!");
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);//重新开始监听
printf("\nAccepte new client:%s:%d", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
memset(c_Message,0,1024); //将原来的client message归零
continue;
}
c_Message[ret] = '\0';
printf("\nReceived: %s\n", c_Message);
}
return 0;
}
client端
#include <WINSOCK2.H>
#include <stdio.h>
#define SERVER_ADDRESS "127.0.0.1" //服务器端IP地址
#define PORT 6000
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")
DWORD WINAPI FunThread(LPVOID);
SOCKET sClient;
SOCKADDR_IN server;
int main()
{
WSADATA wsaData;
char c_Message[MSGSIZE];
WSAStartup(0x0202, &wsaData);
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
/* socket函数用于创建一个套接字
SOCKET socket(int af ,int type,int protocol);
af:标识一个地址家族,通常为AF_INET。
type:标识套接字类型,如果为SOCK_STREAM,表示流式套接字;如果为SOCK_DGRAM,表示数据报套接字.
protocol:标识一个特殊的协议被用于套接字,通常为0,标识采用默认的TCP/IP协议.
*/
memset(&server, 0, sizeof(SOCKADDR_IN)); //先将保存地址的server置为全0
server.sin_family = PF_INET; //声明地址格式是TCP/IP地址格式
server.sin_port = htons(PORT); //指明连接服务器的端口号
server.sin_addr.s_addr = inet_addr(SERVER_ADDRESS); //指明连接服务器的IP地址
connect(sClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN)); //连到刚才指明的服务器上
/*connect函数*/
HANDLE hThread=CreateThread(NULL,0,FunThread,0,0,0);
CloseHandle(hThread);
while (TRUE)
{
printf("Client Send:");
gets(c_Message);
send(sClient, c_Message, strlen(c_Message), 0);
if(!strcmp(c_Message,"exit"))//server让client退出
/*strcmp是C语言中头文件(字符串函数)中定义的一个用于对两组字符串进行比较的函数,它的返回值是int类型*/
exit(1);
}
// 释放连接和进行结束工作
closesocket(sClient);
/*每次调用了WSAStartup函数,你都需要调用WSACleanup函数,通知系统来卸载库文件及清除已分配的资源,这个函数十分简单,没有任何参数*/
WSACleanup();
return 0;
}
DWORD WINAPI FunThread(LPVOID)
{
char s_Message[MSGSIZE];
int ret;
while (TRUE)
{
/*recv函数用于从连接的套接字中接收数据。*/
ret = recv(sClient, s_Message, MSGSIZE, 0);
if(ret==SOCKET_ERROR)
{
printf("\nServer is closed!\n");
exit(1);
}
s_Message[ret] = '\0';
printf("\nReceived: %s\n", s_Message);
if(!strcmp(s_Message,"exit")) //server让client退出
exit(1);
/*退出程序 子程序中:退出主函数,主函数中:退出主函数(和return 不同的是子函数中:返回主函数,主函数中:退出主函数)*/
}
return 0;
}