对于tcp的客户端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser, cli;
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(6000);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = connect(sockfd, (struct sockaddr*)&ser, sizeof(ser));
assert(res != -1);
while(1)
{
printf("please input data: ");
fflush(stdout);
char buff[128] = {0};
fgets(buff,128,stdin);
buff[strlen(buff) - 1] = 0;
if(strcmp(buff,"end") == 0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
char recvbuff[128] = {0};
recv(sockfd, buff, 127, 0);
printf("%s\n",buff);
}
close(sockfd);
}
对于tcp的服务器端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser, cli;
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(6000);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
//绑定 命名
//1.ip地址不对
//2.端口号被占用或者每权限
int res = bind(sockfd, (struct sockaddr*)&ser,sizeof(ser));
assert( res != -1);
listen(sockfd,5);
while(1)
{
int len = sizeof(cli);
int c = accept(sockfd, (struct sockaddr*)&cli,&len);
if( c < 0)
{
printf(" error\n");
return 0;
}
while(1)
{
char recvbuf[128] = {0};
int n = recv(c, recvbuf, 127, 0); //阻塞运行
if( n <= 0)
{
printf("one client break\n");
break;
}
printf("%d:%s\n", c, recvbuf);
send(c, "ok", 2, 0);
}
close(c);
}
}
udp的客户端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
if(argc >= 3)
{
printf("please choose server's IP && port\n");
exit(0);
}
int port = 0;
sscanf(argv[2], "%d", &port);
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser, cli;
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr(argv[1]);
while(1)
{
printf("please input data: ");
fflush(stdout);
char buff[128] = {0};
fgets(buff,128,stdin);
buff[strlen(buff) - 1] = 0;
if(strcmp(buff,"end",3) == 0)
{
close(sockfd);
break;
}
sendto(sockfd,buff,strlen(buff),0,
(struct sockaddr *)&ser,sizeof(ser));
char recvbuff[128] = {0};
recvfrom(sockfd, recvbuff, 127, 0, NULL,NULL);
printf("%s\n", recvbuff);
recv(sockfd, buff, 127, 0);
printf("%s\n",buff);
}
close(sockfd);
}
对于udp的服务器端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser, cli;
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(6500);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
//绑定 命名
//1.ip地址不对
//2.端口号被占用或者每权限
int res = bind(sockfd, (struct sockaddr*)&ser,sizeof(ser));
assert( res != -1);
while(1)
{
char recvbuff[128] = {0};
int len = sizeof(cli);
int n = recvfrom(sockfd, recvbuff, 127, 0,(struct sockaddr*)&cli, &len);
if( n <= 0)
{
printf("recvfrom error\n");
continue;
}
printf("recvbuff: %s\n", recvbuff);
sendto(sockfd, "ok", 2, 0,(struct sockaddr*)&cli, sizeof(cli));
}
close(sockfd);
}
TCP是面向连接 可靠的 字节流式服务
UDP是无连接的 不可靠的 数据报服务
TCP通信主要是包括三个步骤:建立TCP连接通道;传输数据;断开TCP连接通道
三次握手:
1.客户端发送SYN包到服务器端,进入SYN_SEND状态,等待服务器确认
2.服务器收到SYN包,确认客户的SYN,同时自己发送一个SYN+ACK包给客户端,此时服务器进入SYN_RECV状态
3.客户端收到SYN+ACK包之后,发送给服务器ACK确认包,此时二者同时进入连接建立状态
数据传输:
超时重传、快速重传、流量控之、拥塞控制(均是为了提供可靠的字节流服务)
四次挥手:
- 客户端发送一个FIN,提出断开连接的请求
- 服务器收到FIN包之后,对其作出响应,发送一个ACK包给对方,确认这方连接即将关闭
- 等服务器做好关闭准备时,服务器再反方向发送一个FIN给客户端,请求关闭连接请求
- 客户端对服务器所发送的请求进行确认,并发送一个ACK包