服務器:
客戶端:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//創建偵聽socket,把sockfd標記的socket標記為被動socket,被動socket表示這個socket只能用來接收即將到來的連接請求,不再用於讀寫操作和通信,接收連接請求的是accept()
//成功返回0,失敗返回-1設errno
int listen(int sockfd, int backlog);
backlog:排隊等待“被響應”連接請求隊列的最大長度 eg: 接待室的最大長度
//創建連接socket,返回連接socket的文件描述符,成功返回文件描述符,失敗返回-1設errno
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
addr : 結構體指針, 用於帶出客戶端的通信地址
addlen : 結構體指針, 用於帶出通信地址的大小
ATTENTION: listen()把socket()創建的sockfd變為listening socket, 負責偵聽哪個client連接上了(即不但要知道連上沒, 還要知道誰連上了, 這個SOCK_STREAM的socket有這個能力), accept()提取排隊中的最上面的一個client, 給它一個conneted socket, 這樣這個client就可以和server溝通了, 就是說這裡有兩個socket, 一個負責偵聽一個負責通信
//向指定的socket發送指定的數據,成功返回實際發送數據的大小,失敗返回-1設errno
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd: 用於通信的socket描述符(returned by accept())
buf : 被發送數據的緩沖區首地址
len : 被發送數據的大小
flags: 發送的標志, 默認給0
//從指定的socket接收數據,成功返回接收的數據的大小,失敗返回-1設errno
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd: 用於通信的socket描述符(returned by accept())
buf: 接收數據的緩沖區首地址
len: 接收數據的大小
flags: 發送的標志, 默認給0
// tcp/ip server七步走
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(){_
//1.創建socket socket()
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(-1==sockfd)
perror("socket"),exit(-1);
printf("creat socket success\n");
//2.准備通信地址(服務器地址),使用結構體類型
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(8888);
addr.sin_addr.s_addr=inet_addr("176.43.11.211"); //client也用這個server的地址
//3.綁定socket和通信地址,使用bind()
int res=bind(sockfd, (struct sockaddr*)&addr,sizeof(addr)); //client用connect
if(-1==res)
perror("bind"),exit(-1);
printf("bind success\n");
//4.生成偵聽socket: listening socket listen() //client可沒有這一步
res=listen(sockfd,100);
if(-1==res)
perror("listen"),exit(-1);
printf("listen success\n");
//5.響應客戶端連接請求並生成connected socket accept() //client當然沒有這一步
struct sockaddr_in recv_addr;
socklen_t len=sizeof(recv_addr);
int CnnSockfd=accept(sockfd,(struct sockaddr*)&recv_addr,&len);
if(-1==fd)
perror("accept"),exit(-1);
char* ip=inet_ntoa(recv_addr.sin_addr); //存儲client的ip
printf("client$%s connect success\n",ip);
//6.進行通信 send()/recv()
char buf[100]={0};
res=recv(CnnSockfd,buf,sizeof(buf),0); //client是send()
if(-1==res)
perror("recv"),exit(-1);
printf("client %s sent data:%s, size is:%d\n",ip,buf,res);
res=send(CnnSockfd,"I received",12,0); //client是recv()
if(-1==res)
perror("send"),exit(-1);
printf("send data success, size is:%d\n",res);
//7.關閉listening socket和connect socket close() //client只關閉sockfd就行, 因為就這一個fd
res=close(CnnSockfd);
if(-1==res)
perror("close"),exit(-1);
res=close(sockfd);
if(-1==res)
perror("close"),exit(-1);
printf("close success\n");
return 0;
}
//創建server, 用多進程同時響應多個client的請求, 當client發來 “bye”的時候斷開連接, 按下Ctrl+C關閉服務器
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h> //省略了幾個頭文件
int sockfd; //全局變量
void fa(int signo){
printf("closing server...\n");
sleep(3);
int res=close(sockfd);
if(-1==res)
perror("close"),exit(-1);
printf("server closed\n");
exit(0);
}
int main(){
… //同上一個程序
//set SIGINT
printf("Press ctrl+c to close server\n");
if(SIG_ERR==signal(SIGINT,fa)) //整個程序,包括第一個while(1)是通過信號處理終止的
perror("signal"),exit(-1);
while(1){ //只要有client接入就創建新進程與之通信
struct sockaddr_in recv_addr;
socklen_t len=sizeof(recv_addr);
int CnnSockfd=accept(sockfd,(struct sockaddr*)&recv_addr,&len);
//如果偵聽隊列裡面有client就accept(), 否則就在這阻塞著,不繼續執行,除非遇到Ctrl+C終止整個進程
if(-1==CnnSockfd)
perror("accept"),exit(-1);
char *ip=inet_ntoa(recv_addr.sin_addr);
printf("client:%s linked\n",ip);
pid_t pid=fork();
if(-1==pid)
perror("fork()"),exit(-1);
if(0==pid){
if(SIG_ERR==signal(SIGINT,SIG_DFL))
perror("signal"),exit(-1);
res=close(sockfd); //每個child處理一個client,所以已經不需要listening socket了,可以把它關了
if(-1==res)
perror("close"),exit(-1);
while(1){ //只要client發數據就處理,除非遇到 “bye”
char buf[100]={0};
res=recv(CnnSockfd,buf,sizeof(buf),0);
if(-1==res)
perror("recv"),exit(-1);
printf("client%s,data sent:%s\n",ip,buf);
if(!strcmp(buf,"bye")){ //遇到“bye”就不再待命,break掉准備斷開連接
printf("client%s has been unlinked\n",ip);
break;
}
res=send(CnnSockfd,"I received!",12,0);
if(-1==res)
perror("send"),exit(-1);
}
res=close(CnnSockfd); //斷開連接即close(相應的connected socket)
if(-1== res)
perror("close"),exit(-1);
exit(0); //斷開了連接了,就可以exit子進程了
}
res=close(CnnSockfd); //
if(-1==res)
perror("close"),exit(-1);
}
return 0;
}