程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C指針原理(90)-LINUX應用(4)-帶超時處理的tcp服務

C指針原理(90)-LINUX應用(4)-帶超時處理的tcp服務

編輯:關於C語言

一、端口

1、0-1023:預留端口,超級用戶使用

2、1024-49151:已經注冊的端口號

3、49152-65535:可自由使用的端口或動態端口

二、套接字類型

1、SOCK_STREAM(字節流套接字):面向連接,可靠的全雙工字節流。對於AF_INET來說,建立TCP連接

2、SOCK_DGRAM(數據報套接字):不保證數據正確分發,不保證發送數據的訓序。對於AF_INET來說,建立UDP連接

3、SOCK_RAW(原始套接字)

三、建立套接字

int fd;

fd=socket(AF_INET,SOCK_STREAM,0);//除使用SOCK_RAW外,最後一個protocol被設置為0,AF_INET為套接口

四、應用

1.server

deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcps
server wait....
............................
server read :myhaspl

server send :hello
.....
server read :myhaspl

server send :hello
2.client
deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcpc
client send....
client send :myhaspl


client read :hello


deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcpc
client send....
client send :myhaspl


client read :hello


deepfuture@deepfuture-laptop:~/private/mytest$

本博客所有內容是原創,如果轉載請注明來源

http://blog.csdn.net/myhaspl/


3.source
1)server
C代碼
#include
#include
#include
#include
#include
//myhaspl
ssize_t readn(int fd,void *ptr,size_t maxcn){//讀取n個字符,maxc為讀取的數目
size_t noreadcn,readcn;
char *buf=ptr;



noreadcn=maxcn;
while(noreadcn>0){
if ( (readcn=read(fd,buf,noreadcn))<0){//讀數據

if (errno==EINTR) {//數據讀取前,操作被信號中斷
perror("中斷錯誤");
readcn=0;
}
else {return -1;}//無法修復錯誤,返回讀取失敗
}
else if(readcn==0) break;//EOF


noreadcn-=readcn;//讀取成功,但是如果讀取的字符數小於maxc,則繼續讀,因為可能數據還會繼續通過網絡送過來
buf+=readcn;
if (*buf==0) break;//如果讀到字符串結尾標志則退出,必須有這句,否則會死循環
}



return (maxcn-noreadcn);
}

ssize_t writen(int fd,void *ptr,size_t maxcn){//寫入n個字符
size_t nowritecn,writecn;
char *buf=ptr;


nowritecn=maxcn;
while(nowritecn>0){
if((writecn=write(fd,buf,nowritecn))<=0){//寫數據

if (errno==EINTR) {//數據寫前,操作被信號中斷
perror("中斷錯誤");
writecn=0;
}
else {return -1;}//無法修復錯誤,返回讀取失敗
}


nowritecn-=writecn;
buf+=writecn;

}

return (maxcn-nowritecn);
}

int main(void){
int fd;
int addresslen;
struct sockaddr_in address;//地址信息結構
int pid;
int rc;
fd_set fdset;




//建立socket
fd=socket(AF_INET,SOCK_STREAM,0);//fd為socket
if (fd==-1){//錯誤,類型從errno獲得
perror("error");//perror先輸出參數,後跟":"加空格,然後是errno值對應的錯誤信息(不是錯誤代碼),最後是一個換行符。
}

//bind 到socket fd
address.sin_family=AF_INET;//IPV4協議,AF_INET6是IPV6
address.sin_addr.s_addr=htonl(INADDR_ANY);//l表示32位,htonl能保證在不同CPU的相同字節序
address.sin_port=htons(1253);//端口號,s表示16位
addresslen=sizeof(address);


bind(fd,(struct sockaddr *)&address,addresslen);//bind

//建立socket隊列,指定最大可接受連接數
rc=listen(fd,32);//最多接收32個連接,開始監聽
//int listen(int sockfd, int backlog)返回:0──成功, -1──失敗
//內核會在自己的進程空間裡維護一個隊列以跟蹤這些完成的連接但服務器進程還沒有接手處理或正在進行的連接
if (rc==-1) {
perror("listen error");//監聽失敗
exit(1);
}
printf("server wait....\n");
while(1){

struct sockaddr_in clientaddress;
int address_len;
int client_sockfd;
char mybuf[100];
char *buf="hello\n";
struct timeval timeout;//超時結構體
//超時為2秒
timeout.tv_sec=1;
timeout.tv_usec=0;
//設置fdset
FD_ZERO(&fdset);//清除fdset
FD_CLR(fd,&fdset);//清除fd的標志
FD_SET(fd,&fdset);//設置標志
//select
if ((select(fd+1,&fdset,NULL,NULL,&timeout))<0){
perror("select error");
fflush(stdout);
}
//等待連接,使用新的進程或線程來處理連接

fflush(stdout);
address_len=sizeof(clientaddress);
if(FD_ISSET(fd,&fdset)){
//如果有連接到來
client_sockfd=accept(fd,(struct sockaddr *)&clientaddress,&address_len);//client_sockfd可理解為一個文件句柄,能用read和write操作。client_address是客戶端信息結構 myhaspl

//fork進程來處理每個客戶的連接
pid=fork();
if (pid<0){//錯誤
printf("error:%s\n",strerror(errno));//strerror將errno映射為一個錯誤信息串 myhaspl
close(client_sockfd);
exit(1);
}

if (pid==0){ //子進程處理每個客戶端的數據
close(fd);//子進程關閉不需要它處理的監聽資源

//讀取數據 myhaspl
bzero(mybuf,100);
readn(client_sockfd,(void *)mybuf,100);
printf("\nserver read :%s",mybuf);
//發送數據
writen(client_sockfd,(void *)buf,strlen(buf)+1);
printf("\nserver send :%s",buf);
close(client_sockfd);
exit(0);
}
else {//父進程
close(client_sockfd);//父進程不處理客戶端連接,因此關閉,但並不意味著把子進程的處理句柄關閉,因為子進程繼承了父進程的client_sockfd資源 myhaspl
}
}else{
printf(".");
fflush(stdout);
}
}
}
2) client
C代碼
#include
#include
#include
#include
#include
//myhaspl
ssize_t readn(int fd,void *ptr,size_t maxcn){//讀取n個字符,maxc為讀取的數目
size_t noreadcn,readcn;
char *buf=ptr;


noreadcn=maxcn;
while(noreadcn>0){
if ( (readcn=read(fd,buf,noreadcn))<0){//讀數據

if (errno==EINTR) {//數據讀取前,操作被信號中斷 myhaspl
perror("中斷錯誤");
readcn=0;
}
else {return -1;}//無法修復錯誤,返回讀取失敗
}
else if(readcn==0) break;//EOF myhaspl

noreadcn-=readcn;//讀取成功,但是如果讀取的字符數小於maxc,則繼續讀,因為可能數據還會繼續通過網絡送過來
buf+=readcn;
if (*buf==0) break; //如果讀到字符串結尾標志則退出,必須有這句,否則會死循環 myhaspl
}

return (maxcn-noreadcn);
}

ssize_t writen(int fd,void *ptr,size_t maxcn){//寫入n個字符
size_t nowritecn,writecn;
char *buf=ptr;

nowritecn=maxcn;
while(nowritecn>0){
if((writecn=write(fd,buf,nowritecn))<=0){//寫數據
if (errno==EINTR) {//數據寫前,操作被信號中斷
perror("中斷錯誤");
writecn=0;
}
else {return -1;}//無法修復錯誤,返回讀取失敗
}

nowritecn-=writecn;
buf+=writecn;

}
return (maxcn-nowritecn);
}

int main(void){
int fd;
int addresslen;
struct sockaddr_in address;//地址信息結構 myhaspl
int pid;
char mybuf[100];
char *buf="myhaspl\n";
int rc;


fd=socket(AF_INET,SOCK_STREAM,0);//建立socket
if (fd==-1){//錯誤,類型從errno獲得
perror("error");//perror先輸出參數,後跟":"加空格,然後是errno值對應的錯誤信息(不是錯誤代碼),最後是一個換行符。 myhaspl
}

printf("client send....\n");
fflush(stdout);

//連接
address.sin_family=AF_INET;//IPV4協議,AF_INET6是IPV6 myhaspl
address.sin_addr.s_addr=inet_addr("127.0.0.1");//l表示32位,htonl能保證在不同CPU的相同字節序
address.sin_port=htons(1253);//端口號,s表示16位 myhaspl
addresslen=sizeof(address);
rc=connect(fd,(struct sockaddr *)&address,addresslen);//連接服務器 myhaspl
if (rc==-1){//rc=0成功,rc=-1失敗 myhaspl
perror("連接錯誤");
exit(1);
}
//發送數據
writen(fd,(void *)buf,strlen(buf)+1);
printf("client send :%s\n",buf);
//讀取數據
bzero(mybuf,100);
readn(fd,(void *)mybuf,100);
printf("client read :%s\n",mybuf);
close(fd);
exit(0);

}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved