资源描述
程序阅读范例二:套接字编程,分server和Client两部分
1) server.c - 简单 TCP/UDP 套节字服务器程序 windows环境
/*******************************************************\
* server.c - 简单 TCP/UDP 套节字服务器程序 windows环境 *
\*******************************************************/
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
unsigned short port= 5001; //端口号
int socket_type = SOCK_DGRAM; //缺省使用TCP连接
char Buffer[1280]; //收发缓冲区
int retval, fromlen, i, isconnected = 0; //临时变量
struct sockaddr_in local, from; //套节字地址结构变量
SOCKET listen_socket, msgsock; //套节字变量
WSADATA wsaData; //windows套节字信息
//先输入服务器程序所需要的基本信息:端口号,套节字类型
printf("请输入端口号( >5000 ):");
scanf("%d", &i);
if(i < 5000 || i > 65535)
printf("不正确的端口号%d,用缺省端口号5001\n",i);
else
port = i;
printf("请输入套节字类型( 1,TCP; 2, UDP ):");
scanf("%d", &i);
if(i == 1)
socket_type = SOCK_STREAM;
else if(i == 2)
socket_type = SOCK_DGRAM;
else
printf("不正确的输入%d,使用TCP数据流\n",i);
//在windows环境下,需要先初始化协议栈
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
printf("WSAStartup 失败,错误号:%d\n", retval);
WSACleanup();
return -1;
}
//建立套节字
listen_socket = socket(AF_INET, socket_type, 0);
if (listen_socket == INVALID_SOCKET)
{
printf("socket()失败,错误号:%d\n", WSAGetLastError());
WSACleanup();
return -1;
}
// 拷贝 解析的信息到sockaddr_in结构中
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(port);
//邦定网络地址到套节字
if (bind(listen_socket,(struct sockaddr*)&local, sizeof(local) ) == SOCKET_ERROR)
{
printf("bind()失败,错误号:%d\n", WSAGetLastError());
WSACleanup();
return -1;
}
//对于流式套节字,让套节字处于监听状态,等待连接到来
if (socket_type != SOCK_DGRAM)
{
if (listen(listen_socket,5) == SOCKET_ERROR)
{
printf("listen()失败,错误号:%d\n", WSAGetLastError());
WSACleanup();
return -1;
}
}
printf("监听端口:%d, 使用协议:%s\n", port,
(socket_type == SOCK_STREAM)? "TCP": "UDP");
while(1)
{
fromlen =sizeof(from);
if (socket_type == SOCK_DGRAM )
msgsock = listen_socket;
else if( isconnected == 0)
{//对于TCP连接,如果没有连接,等待一个连接的到来
msgsock = accept(listen_socket,(struct sockaddr*)&from, &fromlen);
if (msgsock == INVALID_SOCKET)
{
printf("accept()失败,错误号:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
isconnected = 1;
printf("从%s收到连接, 端口是:%d\n", inet_ntoa(from.sin_addr), htons(from.sin_port));
}
//等待接收网络信息
if (socket_type != SOCK_DGRAM)
retval = recv(msgsock, Buffer, sizeof (Buffer), 0 ); //面向tcp,类似BSD read()
else
{
retval = recvfrom(msgsock, Buffer, sizeof (Buffer), 0,
(struct sockaddr *)&from, &fromlen); //面向UDP
printf("从%s收到数据报,端口是:%d\n", inet_ntoa(from.sin_addr), htons(from.sin_port));
}
//结果判断
if (retval == SOCKET_ERROR)
{
printf("recv()失败,错误号:%d\n", WSAGetLastError());
closesocket(msgsock);
continue;
}
else if (retval == 0)
{
printf("客户端关闭连接\n");
closesocket(msgsock);
continue;
}
else //正常接收
{
printf("收到 %d 字节的数据:%s \n", retval, Buffer);
if (socket_type != SOCK_DGRAM)
{//对于TCP连接,我们收到"exit"有一个关闭连接的操作
if(!stricmp(Buffer, "exit"))
{
printf("关闭TCP 连接,等待下一次连接...\n");
closesocket(msgsock);
isconnected = 0;
continue;
}
}
}
//信息回送
printf("将同样的信息回送给客户端...\n\n");
if (socket_type != SOCK_DGRAM)
retval = send(msgsock, Buffer, strlen(Buffer)+1, 0); //面向tcp,类似BSD write()
else
retval = sendto(msgsock, Buffer, strlen(Buffer)+1, 0,
(struct sockaddr *)&from, fromlen); //面向UDP
if (retval == SOCKET_ERROR)
{
printf("send()失败,错误号:%d\n", WSAGetLastError());
}
//程序的一个退出条件
if(!stricmp(Buffer, "quit"))
break;
}
WSACleanup();
return 0;
}
2) client.c - 简单的 TCP/UDP 套节字客户程序 windows环境
/******************************************************\
* client.c - 简单的 TCP/UDP 套节字客户程序 windows环境 *
\******************************************************/
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main(void)
{
unsigned short port = 5001; //端口号
int socket_type = SOCK_STREAM; //缺省使用TCP连接
char Buffer[1280]; //收发缓冲区
unsigned int addr; //IP地址变量
int retval,i; //临时变量
struct sockaddr_in server, from; //套节字地址结构变量
struct hostent *hp; //主机信息结构变量指针
WSADATA wsaData; //windows套节字信息
SOCKET conn_socket; //套节字变量
//先输入客户程序所需要的基本信息:服务器地址,端口号,套节字类型
printf("请输入服务器地址:");
scanf("%s", Buffer);
printf("请输入端口号( >5000 ):");
scanf("%d", &i);
if(i < 5000 || i > 65535)
printf("不正确的端口号%d,用缺省端口号5001\n", i);
else
port = i;
printf("请输入套节字类型( 1,TCP; 2, UDP ):");
scanf("%d",&i);
if(i == 1)
socket_type = SOCK_STREAM;
else if(i == 2)
socket_type = SOCK_DGRAM;
else
printf("不正确的输入%d,使用TCP数据流\n", i);
//在windows环境下,需要先初始化协议栈
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
printf("WSAStartup 失败,错误号:%d\n",retval);
WSACleanup();
return -1;
}
//取得主机IP地址
if (isalpha(Buffer[0])) //是域名或命名地址
hp = gethostbyname(Buffer);
else
{
addr = inet_addr(Buffer);//是点分地址
hp = gethostbyaddr((char *)&addr,4,AF_INET);
}
if (hp == NULL )
{
printf("不能解析地址[%s]: 错误号%d\n", Buffer, WSAGetLastError());
WSACleanup();
exit(1);
}
// 拷贝 解析的信息到sockaddr_in结构中
memset(&server,0,sizeof(server));
memcpy(&(server.sin_addr),hp->h_addr,hp->h_length);
server.sin_family = hp->h_addrtype;
server.sin_port = htons(port);
//建立套节字
conn_socket = socket(AF_INET,socket_type,0);
if (conn_socket <0 )
{
printf("socket()失败,错误号:%d\n", WSAGetLastError());
WSACleanup();
return -1;
}
//对于流式套节字,需要先建立连接
//其实也可以使用connect(),send(),recv()等函数在windows里面一样实现数据报套节字功能
if(socket_type != SOCK_DGRAM)
{
printf("正在连接到: %s\n",hp->h_name);
if (connect(conn_socket,(struct sockaddr*)&server,sizeof(server)) == SOCKET_ERROR)
{
printf("connect()失败,错误号:%d\n",WSAGetLastError());
closesocket(conn_socket);
WSACleanup();
return -1;
}
}
while(1)
{
//得到要发送的信息字符串
puts("\n输入送到服务器的信息:");
gets(Buffer);
if(!strlen(Buffer)) //如果没有输入信息,继续循环
continue;
//发送网络信息
if(socket_type != SOCK_DGRAM)
retval = send(conn_socket, Buffer, strlen(Buffer)+1, 0); //面向tcp,类似BSD write()
else
retval = sendto(conn_socket, Buffer, strlen(Buffer)+1, 0, //发送字符串的时候,须将字符串的结束符\0发送
(struct sockaddr*)&server, sizeof(server)); //面向UDP
if (retval == SOCKET_ERROR)
{
printf("发送失败,错误号: %d\n", WSAGetLastError());
break;
}
else
printf("发送信息:%s\n", Buffer);
//接收网络信息
i = sizeof(from);
if(socket_type != SOCK_DGRAM)
retval = recv(conn_socket, Buffer, sizeof(Buffer), 0 );//面向tcp,类似BSD read()
else
retval = recvfrom(conn_socket, Buffer, sizeof(Buffer), 0,
(struct sockaddr*)&from, &i); //面向UDP
if (retval == SOCKET_ERROR)
{
printf("接收信息失败,错误号:%d\n",WSAGetLastError());
break;
}
else if (retval == 0) // 对于面向连接的套节字,需要判断对方是否关闭连接
{
printf("服务器关闭连接\n");
break;
}
else //正确接收到网络信息
printf("收到 %d 字节信息:%s \n", retval, Buffer);
//程序的一个退出条件
if(!stricmp(Buffer, "quit"))
break;
}
//关闭套节字
closesocket(conn_socket);
WSACleanup();
return 0;
}
展开阅读全文