资源描述
编号
TCP/IP合同与网络编程
期末大作业
题目: 基于Socket网络通信
物联网工程 学院 计算机科学与技术 专业
摘 要
课题是基于TCP/UDP合同编写聊天室系统。聊天室系统重要涉及注册、登陆、群聊、单聊、显示在线人员和退出功能。系统重要涉及客户端、服务器端和客户显示端。其中客户端与服务器端连接基于TCP合同,服务器端向客户显示端发送数据是基于UDP合同。
课题是网络合同栈中传播层应用,在网络成基本上,在传播层中使用网络套接字,达到数据传送目,从而实现聊天室系统功能。
核心词:TCP/UDP;聊天室;网络套接字;数据传送
目录
第1章 总体设计 2
第2章 客户端设计 3
2.1 发送端设计 3
2.11 流程图 3
2.12 代码 3
2.2接受端设计 3
2.21 流程图 3
2.22 代码 3
第3章 服务器设计 4
3.1 流程图 4
3.2 代码 4
第4章 运营成果 5
第1章 总体设计
1 原理
1.1 TCP
在面向连接数据流(SOCK_STREAM)传播过程中,设计基于TCP/IP合同程序是传播层使用TCP合同,它最大特点是在通信之前要在客户和服务器之间先建立连接,在数据传播完毕后要关闭连接,释放网络资源。
面向连接客户/服务器程序工作模型如下:
1.2 UDP
无连接数据报(SOCK_DGRAM)传播服务在传播层使用合同时UDP合同。与面向连接通信合同过程不同,它最大特点就是必要要在客户和服务器之间建立连接,通信任何一方可以先发送数据,这样一方面发送数据一方就成为客户端,而接受数据一方就是服务器端。在数据传播完毕后,只要关闭套接口,释放网络资源,通信过程就结束了。
无连接数据包传播服务通信是,客户端与服务器端所使用函数是类似。
面向无连接客户/服务器程序工作模型如下:
1.3 流程图
基于TCP/UDP聊天室系统涉及客户端、客户显示端和服务器端三某些。功能重要是注册、登陆、群聊、单聊、显示在线人员和退出。客户端与服务器端连接合同基于TCP合同,服务器端发送功能基于UDP合同。客户端与服务器端建立连接后,客户端进行操作,将数据发送至客户显示端。
第2章 客户端设计
2.11 流程图
2.12 代码
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#define BUFFER_SIZE 1024
void MySendMessage(SOCKET sSocket,char *response,int responseLen);
int main(int argc, char **argv)
{
WSADATA wsaData;
sockaddr_in ser,cli;
SOCKET sClient,wchysClient;
int iLen,wchyiLen;
int iRecv;
char send_buf[1000];
char recv_buf[BUFFER_SIZE];
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup()\n");
return 0;
}
printf("手动连接模式中....\n");
char szServer[256]; //连接服务器地址,IP地址
printf("请输入即将连接服务器IP地址:");
gets(szServer);
ser.sin_family = AF_INET;
ser.sin_port = htons(5050);
ser.sin_addr.s_addr = inet_addr(szServer);
char user[20],password[20];
char str[100],str1[100],wchystr[100];
bool hasLogin=false;
//只能绑定一次,开始放在了循环里,555
wchysClient=socket(AF_INET,SOCK_DGRAM,0);
if(wchysClient==INVALID_SOCKET){printf("socket()Faild:%d\n",WSAGetLastError());return 0;}
cli.sin_family=AF_INET;
cli.sin_port=htons(5053);
cli.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(wchysClient,(LPSOCKADDR)&cli,sizeof(cli))==SOCKET_ERROR)
{printf("bind()Faild:%d\n",WSAGetLastError());return 0;}
wchyiLen=sizeof(cli);
memset(recv_buf,0,sizeof(recv_buf));
sClient = socket(AF_INET, SOCK_STREAM, 0);
if (sClient == INVALID_SOCKET)
{
printf("socket()\n");
return 0;
}
if (connect(sClient, (sockaddr*)&ser, sizeof(ser)) == INVALID_SOCKET)
{
printf("socket()\n");
return 0;
}
else
{
bool hasLogin=false;
while(!hasLogin){
printf("--------------------------------\n");
printf("0.注册\n");
printf("1.登陆\n");
printf("2.退出\n");
printf("请输入相应数字:\n>");
scanf("%s",&str);
switch(str[0])
{
case '0':
printf("顾客名:");
scanf("%s",user);
printf("密 码:");
scanf("%s",password);
strcpy(send_buf,"0");
strcat(send_buf,user);
strcat(send_buf,"@");
strcat(send_buf,password);
MySendMessage(sClient, send_buf, sizeof(send_buf));
break;
case '1':
printf("顾客名:");
scanf("%s",user);
printf("密 码:");
scanf("%s",password);
strcpy(send_buf,"1");
strcat(send_buf,user);
strcat(send_buf,"@");
strcat(send_buf,password);
MySendMessage(sClient, send_buf, sizeof(send_buf));
iRecv=recvfrom(wchysClient,recv_buf,BUFFER_SIZE,0,(SOCKADDR*)&cli,&wchyiLen);
if(iRecv==SOCKET_ERROR)
{printf("recvfrom()Faild:%d\n",WSAGetLastError());return 0;}
else if(iRecv==0) break;
else
{// 接受到了对的数据
printf("recv:%s\n",recv_buf);
}
if(recv_buf[0]=='@'&&recv_buf[1]=='@'){
hasLogin=0;
system("cls");
printf("登录失败!请重新登录或注册后登录^_^\n");
}
if(recv_buf[0]=='*'&&recv_buf[1]=='*'){
hasLogin=0;
system("cls");
printf("已经在其她地方登陆\n");
printf("登录失败!请重新选取顾客登录或注册后登录^_^\n");
}
if(recv_buf[0]=='#'&&recv_buf[1]=='#'){
hasLogin=1;
system("cls");
printf("登录成功^_^\n");
bool wchyhasLogin=false;
while(!wchyhasLogin){
printf("--------------------------------\n");
printf("0.群聊\n");
printf("1.单聊\n");
printf("2.在线顾客\n");
printf("3.退出\n");
printf("请输入相应数字:\n>");
scanf("%s",&wchystr);
switch(wchystr[0])
{
case '0':
wchyhasLogin=1;
printf("输入exit退出。\n");
printf("--------------------------------\n");
while(wchyhasLogin)
{
printf(">");
scanf("%s",&str);
if(strcmp(str,"exit")!=0)
{
strcpy(send_buf,"2");
strcat(send_buf,user);
strcat(send_buf,"@");
strcat(send_buf,str);
MySendMessage(sClient, send_buf, sizeof(send_buf));
}
else
{
system("cls");
wchyhasLogin=0;
}
}
break;
case '1':
wchyhasLogin=1;
printf("请输入单聊对象顾客名:");
scanf("%s",&str1);
strcpy(send_buf,"5");
strcat(send_buf,str1);
strcat(send_buf,"@");
strcat(send_buf,user);
strcat(send_buf,"*");
strcat(send_buf,"__Welcome__To__Single__Chat...");
MySendMessage(sClient, send_buf, sizeof(send_buf));
iRecv=recvfrom(wchysClient,recv_buf,BUFFER_SIZE,0,(SOCKADDR*)&cli,&wchyiLen);
if(iRecv==SOCKET_ERROR)
{printf("recvfrom()Faild:%d\n",WSAGetLastError());return 0;}
else if(iRecv==0) break;
else
{// 接受到了对的数据
//printf("recv:%s\n",recv_buf);
}
if(recv_buf[0]=='^'&&recv_buf[1]=='^'){
wchyhasLogin=0;
system("cls");
printf("单聊对象不存在,退出了单聊模式\n");
}
if(recv_buf[0]=='&'&&recv_buf[1]=='&'){
wchyhasLogin=0;
system("cls");
printf("单聊对象未在线,退出了单聊模式\n");
}
if(recv_buf[0]=='%'&&recv_buf[1]=='%'){
printf("输入exit退出。\n");
printf("--------------------------------\n");
while(wchyhasLogin)
{
printf(">");
scanf("%s",&str);
if(strcmp(str,"exit")!=0)
{
strcpy(send_buf,"5");
strcat(send_buf,str1);
strcat(send_buf,"@");
strcat(send_buf,user);
strcat(send_buf,"*");
strcat(send_buf,str);
MySendMessage(sClient, send_buf, sizeof(send_buf));
}
else
{
system("cls");
wchyhasLogin=0;
}
}
}
break;
case '2':
strcpy(send_buf,"4");
strcat(send_buf,user);
strcat(send_buf,"@");
strcat(send_buf,str);
MySendMessage(sClient, send_buf, sizeof(send_buf));
system("cls");
break;
case '3':
strcpy(send_buf,"3");
strcat(send_buf,user);
strcat(send_buf,"@");
MySendMessage(sClient, send_buf, sizeof(send_buf));
hasLogin=0;
wchyhasLogin=1;
system("cls");
break;
default:
system("cls");
printf("请输入对的信息\n");
break;
}
}
}
break;
case '2':
exit(0);
break;
default:
system("cls");
printf("请输入对的信息");
}
}
}
system("PAUSE");
closesocket(sClient);
WSACleanup();
return 0;
}
void MySendMessage(SOCKET sSocket,char *response,int responseLen)
{
int iSend;
iSend=send(sSocket,response,responseLen,0);
if(iSend==SOCKET_ERROR)
{
printf("send()Failed.:%d\n",WSAGetLastError());
}
else if(iSend==0) ;
else
{
//printf("send() succeeded !\n");
printf("----------------------\n");
}
}
2.2接受端设计
2.21 流程图
2.22 代码
#include<stdlib.h>
#include<string.h>
//for main.cpp(1.cpp)
#define DEFAULT_PORT 5051//FOR RECV
#define DEFAULT_PORTSEND 5052//FOR SEND
#define BUFFER_LENGTH 1000
const bool Debug=0;
#define MaxUser 1000
//--------------------------------------------------------------------------------//
//当程序遇到异常而结束时会示出错误而退出
//--------------------------------------------------------------------------------//
//成员构造信息
#define UserNameLen 200
#define PasswordLen 200
typedef struct
{
char UserName[200];
char Password[200];
bool Log;//与否登陆
char Ip[20];
}
UserData;
#define thefile "config.txt"
bool SaveData(UserData **userdata,int userdatap);
//--------------------------------------------------------------------------------//
//初始化顾客数据导入
int findUser(UserData **data,int num,char *name)
{
int i;
for(i=0;i<=num;i++)
{
if(strcmp(name,data[i]->UserName)==0) return i;
}
return -1;
}
void deal(char *str,UserData **data,int &num,char *response,char *ip)
{
char User[UserNameLen];
char Pass[PasswordLen];
//第一位字符是功能号
// 0 注册
// 1 登陆
// 2 会话
// 3 退出
int i,t;
if(str[0]=='0')
{
//注册消息格式为 0+name+@+password
for(i=1;i<strlen(str);i++)
if(str[i]=='@')break;
str[i]='\0';
strcpy(User,str+1);
strcpy(Pass,str+i+1);
t=findUser(data,num,User);
if(t==-1)
{//该顾客名不存在,可以注册
num++;
data[num]=(UserData *)malloc(sizeof(UserData));
if(data[num]==NULL){printf("[+]ERROR:malloc failed\n");exit(1);}
strcpy(data[num]->UserName,User);
strcpy(data[num]->Password,Pass);
data[num]->Log=0;
memset(data[num]->Ip,'\0',sizeof(data[num]->Ip));
printf("%s 顾客注册成功\n",User);
//--------------------------------------------------注册完毕
//返回成功信息
strcpy(response,"00");//第一位是功能号 第二位是状态号 0表达到功 1表达失败
SaveData(data,num);
}
else
{//fail
printf("%s 顾客注册失败\n",User);
//-----------------------------------------------注册失败
strcpy(response,"01");
}
}
else if(str[0]=='1')
{
//登陆消息格式为 1+name+@+password
for(i=1;i<strlen(str);i++)
if(str[i]=='@')break;
str[i]='\0';
//printf("i=%d\n",i);
strcpy(User,str+1);
strcpy(Pass,str+i+1);
t=findUser(data,num,User);
if(t!=-1)
{//找到该顾客
//printf("Pass=%s",Pass);
//printf("Pawd=%s",data[t]->Password);
if(strcmp(Pass,data[t]->Password)==0 && data[t]->Log==0)
{//密码验证成功
printf("%s 登陆成功\n",User);
data[t]->Log=1;
strcpy(data[t]->Ip,ip);
strcpy(response,"10");
}
else if(strcmp(Pass,data[t]->Password)==0 && data[t]->Log==1){
printf("%s 已经在其她地方登陆\n",User);
strcpy(response,"1@");
}
else
{
printf("%s 登陆密码错误\n",User);
strcpy(response,"11");
}
}
else
{
printf("%s 顾客不存在,登陆失败\n",User);
strcpy(response,"12");
}
}
else if(str[0]=='2')
{
//会话消息格式为 2+'name'+'@'+'(message)'
for(i=1;i<strlen(str);i++)
if(str[i]=='@')break;
str[i]='\0';
strcpy(User,str+1);
t=findUser(data,num,User);
if(t!=-1 && strcmp(data[t]->UserName,User)==0 && strcmp(data[t]->Ip,ip)==0)
{
//表达的确是对的顾客发来会话
strcpy(response,"20");
strcat(response,User);
strcat(response,":");
strcat(response,str+i+1);
printf("%s:%s\n",User,str+i+1);
}
else
{
strcpy(response,"21");
printf("非对的顾客发来会话,不予解决!\n");
}
}
else if(str[0]=='3')
{
//会话消息格式为 3+'name'+'@'+'(message)'
for(i=1;i<strlen(str);i++)
if(str[i]=='@')break;
str[i]='\0';
strcpy(User,str+1);
t=findUser(data,num,User);
if(t!=-1 && strcmp(data[t]->UserName,User)==0 && strcmp(data[t]->Ip,ip)==0)
{
//表达的确是对的顾客发来会话
strcpy(response,"30");
data[t]->Log=0;
memset(data[t]->Ip,'\0',sizeof(data[t]->Ip));
printf("%s 退出\n",data[t]->UserName);
}
else
{
strcpy(response,"31");
printf("非对的顾客发来会话,不予解决!");
}
}
else if(str[0]=='4')
{
for(i=1;i<strlen(str);i++)
if(str[i]=='@')
break;
str[i]='\0';
strcpy(response,"40");
for(i=0;i<=num;i++)
{
if(data[i]->Log==1){
printf("%s[%s]在线\n",data[i]->UserName,data[i]->Ip);
//printf("%s\n",data[i]->UserName);
strcat(response,data[i]->UserName);
strcat(response," ");
}
else{
//printf("%s",data[i]->Ip);
}
}
}
else if(str[0]=='5')
{
for(i=1;i<strlen(str);i++)
if(str[i]=='@')
break;
str[i]='\0';
strcpy(User,str+1);
printf("%s 顾客接受\n",User);
strcpy(Pass,str+i+1);
for(i=1;i<strlen(Pass);i++)
if(Pass[i]=='*')
break;
Pass[i]='\0';
printf("%s 顾客发送\n",Pass);
t=findUser(data,num,User);
if(t==-1)
{
strcpy(response,"60");
printf("单聊对象不存在");
}
else
{
if(data[t]->Log==0)
{
strcpy(response,"61");
printf("%s 未在线\n",User);
}
else if(data[t]->Log==1){
strcpy(response,"50");
strcat(response,Pass);
strcat(response,":");
strcat(response,Pass+i+1);
printf("%s:%s\n",Pass,Pass+i+1);
printf("%s 在线,可进行聊天\n",User);
}
}
}
}
void MySendMessage(int sSocket,char *response,int responseLen,SOCKADDR* cli,int cliLen)
{
int iSend;
iSend=sendto(sSocket,response,responseLen,0,(SOCKADDR*)cli,cliLen);
if(iSend==SOCKET_ERROR)
{
printf("sendto()Failed.:%d\n",WSAGetLastError());
}
else if(iSend==0) ;
else
{
//printf("sendto() succeeded !\n");
//printf("----------------------\n");
}
}
bool InitData(UserData **s,int num,int &p)//成功返回true 发生错误返回false
{
//-----------------------------------------//
//读取文献信息并返回
FILE *fp;
char UserBuf[UserNameLen];
char PassBuf[PasswordLen];
fp=fopen(thefile,"r");
if(!fp)
{
if(Debug) printf("config文献不存在\n");
}
else
{
if(Debug) printf("find config.txt\n");
while(!feof(fp))
{
//fgets(buf,sizeof(buf),fp);
fscanf(fp,"%s",UserBuf);
fscanf(fp,"%s",PassBuf);
if(Debug) printf("[+]User:%s Password:%s\n",UserBuf,PassBuf);
//add
p++;
s[p]=(UserData *)malloc(sizeof(UserData));
if(!s[p]){printf("[+]ERROR:malloc failed!\n");return false;}
strcpy(s[p]->UserName,UserBuf);
strcpy(s[p]->Password,PassBuf);
s[p]->Log=0;
memset(s[p]->Ip,'\0',sizeof(s[p]->Ip));
}
fclose(fp);
}
return true;
}
bool SaveData(UserData **userdata,int userdatap)
{
FILE *fp;
///建立配备文献
fp=fopen(thefile,"w");
if(!fp){printf("[+]ERROR:无法创立config文献!");return false;};
int i;
for(i=0;i<=userdatap;i++)
{
fprintf(fp,"%s %s",userdata[i]->UserName,userdata[i]->Password);
if(i!=userdatap)fprintf(fp,"\n");
}
fclose(fp);
}
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
#include"ser.h"
//
UserData *userdata[MaxUser];
int userdatap=-1;
#define BUFFER_SIZE 2048
void CompressArrays(WSAEVENT events[], SOCKET sockets[], DWORD *total, int index)
{
for (size_t i = index + 1; i < *total; i++)
展开阅读全文