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號信號,導致進程結束,爲了避免這種情況,要用信號處理函數對信號處理。
//應用:註冊統計信息
//羣聊天室
//雲計算