📄 723.c
字号:
#include "socket.h"
/************关于本文档********************************************
*filename: select-server.c
*purpose: 演示网络异步通讯,这是服务器端程序
*http://www.solaux.com
*****************************************************************/
/**************************************************************************
* 创建监听,读写线程
**************************************************************************/
void* NetThread(void *arg)
{
struct{
int new_fd;
char client_ip[20];
char client_port[6];
}*ClientData;
char SelfIp[20]; // socket的自身ip
char HopPort[4]; // 转发的端口
int HopSocketFd;
memset(HopPort,'\0',4);
ClientData = arg;
int retval;
socklen_t tlen;
fd_set rfds;
int flag = 1;
char HopIp[20]; // 转发的ip
int index;
struct timeval tv;
int maxfd = -1;
char messagebuf[MAXBUF + 1];
char dbbuf[MAXBUF + 1];
int new_fd;
new_fd = (int)ClientData->new_fd; // 取得线程句柄
strcpy(SelfIp,(char *)ClientData->client_ip); // 取得线程ip
pthread_detach(pthread_self()); // 将线程挂出
while (1)
{
FD_ZERO(&rfds); // 把集合清空
FD_SET(0, &rfds); // 把标准输入句柄0加入到集合中
maxfd = 0;
FD_SET(new_fd, &rfds); // 把当前连接句柄new_fd加入到集合中
if (new_fd > maxfd)
maxfd = new_fd;
tv.tv_sec = 1; // 设置最大等待时间
tv.tv_usec = 0;
retval = select(maxfd + 1, &rfds, NULL, NULL, &tv); // 开始等待
if (retval == -1)
{
printf("将退出,select出错! %s", strerror(errno));
break;
}
else if (retval == 0)
continue; // 无消息继续等待
else
{
/*********** 接收 ***********/
if (FD_ISSET(new_fd, &rfds)) // 当前连接的socket上有消息到来则接收对方发过来的消息并显示
{
bzero(messagebuf, MAXBUF + 1);
// 得到转发的IP地址
if (flag == 1)
{
bzero(HopIp, 20);
tlen = recv(new_fd, HopIp, 20, 0); // 接收客户端的消息
flag = 0;
if ((result = KMP(ip_port,HopIp)) != -1) // 查询转发的ip是否在线
{
// 根据ip地址提取端口
while (ip_port[result] != '&')
result ++;
i = 0;
result ++;
while (ip_port[result] != '#')
{
HopPort[i] = ip_port[result];
result ++;
i++;
}
HopPort[i] = 0x00; // 取得发送ip的port
printf("HopPort: %s\n",HopPort);
}
else
{
printf (" 对方不在线!!是否输入离线消息?1 -> 是 , 2 -> 否\n");
gets(flag);
if (flag == 1) // 把ip地址 和 消息存到数据库
{
while(1)
{
bzero(dbbuf, MAXBUF + 1);
printf("请输入离线消息,输入quit退出!\n");
gets(dbbuf);
if (!strncasecmp(messagebuf, "quit", 4)) // 接收到结束标志
break;
if(DataInsert(SelfIp,dbbuf,HopIp) == 0) // 插入
{
printf("insert faile!\n");
return 0;
}
}
}
else
break;
}
}
else
{
tlen = recv(new_fd, messagebuf, MAXBUF, 0); // 接收客户端的消息
if (tlen > 0)
{
if (!strncasecmp(messagebuf, "quit", 4)) // 接收到结束标志
break;
else // 调用发送函数 发送到对方机器
{
/*********** 发送段 ************/
// printf ("The receive message|ip|port is :\t%s\t%s\t%S\n",string,ip,port);
struct sockaddr_in address;
if ((HopSocketFd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket创建出错!");
exit(1);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(HopIp);
address.sin_port = htons(ClientPort);
if ((result = connect(HopSocketFd,(struct sockaddr *)&address,sizeof(address))) == -1)
perror;
// len = write(HopSocketFd,messagebuf,sizeof(messagebuf));
tlen = send(sockfd, messagebuf, strlen(messagebuf), 0);
if (tlen < 0)
printf("发送失败:\t%s\n",strerror(errno));
/*********** 发送段 **************/
// fflush(sockfd)
close(HopSocketFd);
wait(NULL);
}
}
else if (tlen < 0)
{
printf("消息接收失败!错误代码是%d,错误信息是''\n", errno, strerror(errno));
break;
}
}
}
}
}
close(new_fd); // 通信结束,关闭线程句柄
/********************* 线程退出 删除ip和port记录 ***********************/
int IpIndex;
IpIndex = KMP(ip_port,SelfIp); // 取得目标IP的索引
i = IpIndex;
j = 1;
// 得到要删除的长度J
while (ip_port[i] != '#')
{
j++; // ip和port的长度
i++;
}
// 数组元素移位
int m;
m = strlen(ip_port);
for (k = (strlen(ip_port) - IpIndex - j), i = 0 ; k > 0; k--,i++)
ip_port[IpIndex + i] = ip_port[IpIndex + j + i];
for (i = 0; i <= j; i++,m--)
ip_port[m] = 0x00;
/********************* 线程退出 删除ip和port记录 ***********************/
fflush(stdout);
printf("Thread exit!\n");
return (NULL);
}
/*********************************************************************
* socket监听
*********************************************************************/
void NetServer()
{
pthread_t Netthread;
socklen_t sin_size;
struct sockaddr_in their_addr;
struct {
int new_fd;
char client_ip[20];
char client_port[6];
}ClientInfo;
while (1)
{
sin_size = sizeof(struct sockaddr_in);
if ((ClientInfo.new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size)) == -1)
{
printf("Accept error:%s\n",strerror(errno));
break;
}
else
{
//their_addr.sin_addr.s_addr = htonl(ip);
itoa(ntohs(their_addr.sin_port),temp);
strcpy(ClientInfo.client_port,temp);
strcpy(ClientInfo.client_ip,inet_ntoa(their_addr.sin_addr));
strcat(ip_port,inet_ntoa(their_addr.sin_addr));
strcat(ip_port, "&");
strcat(ip_port,temp);
strcat(ip_port, "#");
/*********************************************************************************
* Create process net data thread
* 为线程传递更具移植性参数(即:将整数值传给被调用函数,值的拷贝被推入被调用函数的栈中)
* 传递指针参数时,多个线程同时存取一个共享变量(new_fd)而没有同步措施
**********************************************************************************/
if (pthread_create(&Netthread,NULL,NetThread,&ClientInfo) != 0)
printf("Create server thread failed.\n");
else
printf("Thread server created!\n");
}
usleep(10000);
}
}
/****************************************************************/
/* 求x的y次方 */
/****************************************************************/
int mypow(int x,int y)
{
int z = 1;
if (y == 0)
return z;
else if (y < 0)
return -1;
else
{
while (y > 0)
{
z = x*z;
y --;
}
return z;
}
}
/****************************************************************/
/* 字符串转数字 */
/****************************************************************/
int isdit(char *s)
{
int a = 0;
for (i = 0; i < strlen(s) ;i++)
{
if (isdigit (s[i]) == 0)
return -1;
}
j = (strlen(s) - 1);
for (i = 0; i < strlen(s) ; i++)
{
a = ((int)s[i] - 48) * mypow(10,j) + a;
--j;
}
return a;
}
/****************************************************************/
/* 字符串颠倒 */
/****************************************************************/
void reverse(char s[])
{
int c;
for (i = 0, j = (strlen(s)-1); i < j ;i++, j-- )
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
/****************************************************************/
/* 数字转字符串 */
/****************************************************************/
void itoa(int n,char s[])
{
int sign;
if ((sign = n) < 0)
n = -n;
i = 0;
do{
s[i++] = n % 10 + '0';
}while((n /= 10) > 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
/***************************************************************/
/* 创建socket */
/***************************************************************/
unsigned int CreateSocket()
{
struct sockaddr_in server_addr;
int n = 1;
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
printf("Socket error:%s\n",strerror(errno));
return FALSE;
}
memset(&server_addr, 0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(ServerPort);
server_addr.sin_addr.s_addr = INADDR_ANY; //inet_addr("127.0.0.1");
len_inet = sizeof server_addr;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int)); // 如果服务器终止后,服务器可以第二次快速启动而不用等待一段时间
if(bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr)) == -1)
{
printf("Bind error:%s\n",strerror(errno));
return FALSE;
}
else
printf("Bind ok.\n");
if(listen(sockfd ,MAX_SOCKETFD_NUM) == -1)
{
printf("Listen error:%s\n",strerror(errno));
return FALSE;
}
else
printf("Listen ok.\n");
return TRUE;
}
/****************** 检查信号 ************************/
void CheckConnect()
{
network_flag = 0;
}
/****************************************************************/
/* KMP 算法。可以证明它的时间复杂度为O(m+n) */
/****************************************************************/
/******** 求模式串T的next函数值并存入数组 next **********/
int get_nextval(const char *T,int next[])
{
int j = 0, k = -1;
next[0] = -1;
int i;
while (T[j/*+1*/] != '\0')
{
if (k == -1 || T[j] == T[k])
{
++j;
++k;
if(T[j] != T[k])
next[j] = k;
else
next[j] = next[k];
}
else
k = next[k];
}
/*
for(i = 0; i < j; i++)
{
printf("%d\n",next[i]);
}
*/
return 0;
}
int KMP(const char *Text,const char* Pattern) //const 表示函数内部不会改变这个参数的值。
{
if(!Text || !Pattern || Pattern[0] == '\0' || Text[0]=='\0')
return -1; //空指针或空串,返回-1。
int llen=0;
const char* c = Pattern;
while(*c++ != '\0') //移动指针比移动下标快。
{
++llen; //字符串长度。
}
int* next = (int*)malloc(sizeof(int) * (llen + 1));
// int* next = new int[len+1];
get_nextval(Pattern,next); //求Pattern的next函数值
int index ,i ,j;
i = j = index = 0;
while(Text[i]!='\0' && Pattern[j]!='\0')
{
if(Text[i] == Pattern[j])
{
++i; //继续比较后继字符
++j;
}
else
{
index += j-next[j];
if(next[j] != -1)
j = next[j]; //模式串向右移动
else
{
j = 0;
++i;
}
}
}
// delete []next;
free (next);
if(Pattern[j] == '\0')
return index; //匹配成功
else
return -1;
}
/******************** 主函数 *********************/
main ()
{
int ret;
signal(SIGPIPE,CheckConnect);
ret = CreateSocket();
if (ret == FALSE)
{
printf("Create socket faile.\n");
return FALSE;
}
NetServer();
usleep(10000);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -