1) 服务器端存在的问题:
*recv会阻塞
解决方法:1、多线程技术
2、 超时返回
2)如何用accept获取客户端IP和端口号
3)TCP通信应用场景:注册统计信息、智能聊天、云计算
4)补充知识
计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。
下面是几个字节顺序转换函数:
htonl():把32位值从主机字节序转换成网络字节序
htons():把16位值从主机字节序转换成网络字节序
ntohl():把32位值从网络字节序转换成主机字节序
ntohs():把16位值从网络字节序转换成主机字节序
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/in.h>
void* rcv_data(void* arg);
void save_files(const char* str);
pthread_mutex_t m;
int main()
{
pthread_mutex_init(&m,NULL);
//创建套接字
int socket_listen=socket(AF_INET,SOCK_STREAM,0);
int opt_val=1;
setsockopt(socket_listen,SOL_SOCKET,SO_REUSEADDR,&opt_val,sizeof(opt_val));
//设置文件
//绑定地址
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr=INADDR_ANY;
myaddr.sin_port=htons(6666);
if(-1==bind(socket_listen,(struct sockaddr*)&myaddr,sizeof(myaddr)))
{
perror("bind");
exit(-1);
}
//将套接字设置为监听状态
listen(socket_listen,5);
struct timeval rcv_timeout;//设置超时为100ms
rcv_timeout.tv_sec=0;
rcv_timeout.tv_usec=100000;
int sock_conn;
struct sockaddr_in client_addr;
socklen_t len;
while(1)//一直监听
{
//接受客户端连接请求
len=sizeof(client_addr);
sock_conn=accept(socket_listen,(struct sockaddr*)&client_addr,&len);
setsockopt(sock_conn,SOL_SOCKET,SO_RCVTIMEO,&rcv_timeout,sizeof(rcv_timeout));//设置超时时间
printf("%s:%d已近连接!\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if(sock_conn==-1)
{
perror("accept");
continue;
}
pthread_t tid;
if(0!=pthread_create(&tid,NULL,rcv_data,(void*)sock_conn))
{
perror("pthread_create");
close(sock_conn);
}
}
//7、关闭监听套接字
close(socket_listen);
pthread_mutex_destroy(&m);
return 0;
}
void* rcv_data(void* arg)
{
pthread_detach(pthread_self());
int sock_conn=(int)arg;
//收发数据
char msg[100];
int ret;
ret=recv(sock_conn,msg,sizeof(msg),0);//0表默认,不加额外控制
//阻塞到收到消息,或连接断开
if(ret>0)
{
msg[ret]='\0';
printf("客户端说:%s\n",msg);
save_files(msg);
}
else if(ret==0)
{
printf("接收失败,连接断开\n");
}
else
{
if(errno==EAGAIN || errno==EWOULDBLOCK)
{
printf("接收超时!\n");
}
else
{
printf("其他错误\n");
}
}
strcpy(msg,"收到您的信息");
ret=send(sock_conn,msg,strlen(msg),0);
//6、断开连接,即关闭连接套接字
close(sock_conn);
return NULL;
}
void save_files(const char* str)
{
pthread_mutex_lock(&m);//保证下面三句话不被打断
FILE* fp=fopen("name.txt","a");
fprintf(fp,"%s\n",str);
fclose(fp);
pthread_mutex_unlock(&m);
}
//解决阻塞问题
//1.主线程接电话,然后分配给其他线程receive
//2.超时返回
//端口复用
//显示对方IP
//当客户端send,而服务器端关闭了连接套接字时,服务器进程会收到13号信号,导致进程结束,为了避免这种情况,要用信号处理函数对信号处理。
//应用:注册统计信息
//群聊天室
//云计算