TCP/UDP实现编程
TCP服务器与客户端的连接过程:
客户端与服务器三次握手是在accept和connect之后建立的。
三次握手的过程:
A-->B 发送SYN
B->A 确认发一个ACK,再发一个SYN
A->B 确认发一个ACK
四次挥手过程:
A---->B
发
FIN
B----->A
发
ACK
(
注意:此时,
A--->B
的通道被关闭,
A
无法再向
B
发数据,但是
B--->A
的通道仍然还开着,
B
到
A
的剩下的数据发完之后,
B
才会主动发出分手的
FIN
信号
)
B----->A
发
FIN
A----->B
发
ACK
为什么服务器在分手时需要等待2MSL才真正分手?
答:因为ACK发给对方,需要一个MSL时间,如果对方在这个时间内存收不到ACK会重发一个FIN信号给我,这个信号也要一个MSL时间。这样,如果经过两个MSL时间之后,A收不到任何信号,则可以得出结论:B已经收到了我最后的那个ACK了。
TCP服务器与客户端连接的代码实现:
//tcpserver.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <mqueue.h> //消息队列
#include <signal.h>
#include <semaphore.h>
#include <sys/socket.h> //套接字接口
#include <arpa/inet.h> //网络地址的转换
#include <time.h>
void formattime(char buffer[]){
time_t ticks;
ticks=time(NULL);
snprintf(buffer,sizeof(char)*1024,"%.24s\n",ctime(&ticks));
}
int main(int argc, char const *argv[])
{
int sockd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in sockin;
bzero(&sockin,sizeof(sockin));
sockin.sin_family=AF_INET;
sockin.sin_addr.s_addr=INADDR_ANY;//避免出现两块网卡出现问题
sockin.sin_port=htons(2017);//两个字节
if(bind(sockd,(struct sockaddr*)&sockin,sizeof(sockin))<0){
perror("bind");
exit(EXIT_FAILURE);
}
if(listen(sockd,10)<0){//最多接收十个客户端的连接
perror("listen");
exit(EXIT_FAILURE);
}
while(1){
struct sockaddr_in clientaddr;//用来保存客户端的网络地址
socklen_t clientlen=sizeof(clientaddr);//客户端网络地址的长度
int fd = accept(sockd,(struct sockaddr*)&clientaddr,&clientlen);
if(fd < 0){
perror("accept");
exit(EXIT_FAILURE);
}
char clientip[20];
inet_ntop(AF_INET,&clientaddr.sin_addr,clientip,sizeof(clientip));
printf("客户端%s(%d)已连接.\n",clientip,(ntohs)(clientaddr.sin_port));
char buffer[1024];
formattime(buffer);
write(fd,buffer,strlen(buffer));
close(fd);
}
return 0;
}
//tcpclient.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <mqueue.h> //消息队列
#include <signal.h>
#include <semaphore.h>
#include <sys/socket.h> //套接字接口
#include <arpa/inet.h> //网络地址的转换
#include <time.h>
//argv[1]是IP地址,argv[2]是端口
int main(int argc, char const *argv[])
{
if(argc<3){
printf("usage:filename ipaddress port");
return -1;
}
//创建套接字
int sockfd=socket(AF_INET,SOCK_STREAM,0);
//绑定网络地址
struct sockaddr_in sockin;
sockin.sin_family=AF_INET;
inet_pton(AF_INET,argv[1],&sockin.sin_addr);//将十进制的转换成二进制的形式,不需要长度
sockin.sin_port=htons(atoi(argv[2]));
//连接服务器
int fd;
fd = connect(sockfd,(struct sockaddr*)&sockin,sizeof(sockin));
if(fd<0){
perror("connect");
exit(-1);
}
//读取信息
char buffer[1024]={0};
if(read(sockfd,buffer,sizeof(buffer))<0){
perror("read");
exit(-1);
}
write(1,buffer,strlen(buffer));
close(fd);
return 0;
}
UDP服务器与客户端的连接过程:
UDP服务器与客户端通信代码:
//udpserver.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <mqueue.h> //消息队列
#include <signal.h>
#include <semaphore.h>
#include <sys/socket.h> //套接字接口
#include <arpa/inet.h> //网络地址的转换
#include <time.h>
int main(int argc, char const *argv[])
{
//创建socket
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
//bind
struct sockaddr_in sockin;
sockin.sin_family=AF_INET;
sockin.sin_addr.s_addr=INADDR_ANY;//接收任何网卡的输入,实际为0
sockin.sin_port=htons(2020);
if(bind(sockfd,(struct sockaddr*)&sockin,sizeof(sockin))<0){
perror("bind");
exit(-1);
}
//从客户端读取信息
char buffer[1024]={0};
struct sockaddr_in clientaddr;
socklen_t len=sizeof(clientaddr);
while(1){
recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&clientaddr,&len);
//写回到客户端
sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
}
close(sockfd);
return 0;
}
//udpclient.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <mqueue.h> //消息队列
#include <signal.h>
#include <semaphore.h>
#include <sys/socket.h> //套接字接口
#include <arpa/inet.h> //网络地址的转换
#include <time.h>
//argv[1]是服务器ip地址 argv[2]端口号
int main(int argc, char const *argv[])
{
//创建socket
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in serveraddr;
serveraddr.sin_family=AF_INET;
inet_pton(AF_INET,argv[1],&serveraddr.sin_addr);
serveraddr.sin_port=htons(2020);
//从客户端读取信息
char buffer[1024]={0};
gets(buffer);
sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
bzero(buffer,sizeof(buffer));
socklen_t len=sizeof(serveraddr);
recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,&len);
//将读出的数据写到屏幕上
printf("返回来的数据是:\n");
write(1,buffer,strlen(buffer));
close(sockfd);
return 0;
}