服务器:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
#include <netdb.h> //DNS头文件
(1)
void text1()
{
//创建套接字是 使用IPv4地址类型 SOCK_STREAM 表示面向连接的数据传输方式 么满足这两个条件的协议只有 TCP
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
//htons是将整型变量从主机字节顺序转变成网络字节顺序
serv_addr.sin_port = htons(1234); //将端口
// sock 为 socket 文件描述符,addr 为 sockaddr 结构体变量的指针,addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。
//服务器端要用 bind() 函数将套接字与特定的IP地址和端口绑定起来,
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//进入监听状态,等待用户发起请求
listen(serv_sock, 20);//最大链接上限容量20
//接受客户端请求
while (1)
{
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size=sizeof(clnt_addr);
int clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
//向客户端发送数据
char str[]="hall word12221";
//写
write(clnt_sock,str,sizeof(str));
close(clnt_sock);
}
//关闭套接字
close(serv_sock);
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
//客户端
void text1()
{
//创建套接字是 使用IPv4地址类型 SOCK_STREAM 表示面向连接的数据传输方式 么满足这两个条件的协议只有 TCP
int sock = socket(AF_INET, SOCK_STREAM, 0);
//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
//htons是将整型变量从主机字节顺序转变成网络字节顺序
serv_addr.sin_port = htons(1234); //将端口
//connect() 函数用来建立连接
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//读取服务器传回的数据
char buffer[40];
read(sock, buffer, sizeof(buffer)-1);
printf("Message form server: %s\n", buffer);
//关闭套接字
close(sock);
}
运行结果:Message form server:hall word12221
(2)
//回声服务端
void test2()
{
int serverSock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(1234);
bind(serverSock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
listen(serverSock, 20);
//接受客户端请求
struct sockaddr_in clnAddr;
socklen_t nSize = sizeof(clnAddr);
int clnSock = accept(serverSock, (struct sockaddr*)&clnAddr, &nSize);
char buffer[100];
ssize_t strlen = read(clnSock, buffer, sizeof(buffer)-1);//接受客户端发来的数据
printf("Message from client: %s\n",buffer);
write(clnSock, buffer, strlen);
close(serverSock);
close(clnSock);
}
//回声客户端
void test2()
{
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(1234);
if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {
printf("链接失败\n");
}
//获取用户输入的字符串并发送给服务器
char bufSend[40];
printf("input a string: ");
scanf("%s",bufSend);
write(sock, bufSend, strlen(bufSend));
//接受服务器传回的数据
char bufRecev[100];
read(sock, bufRecev, sizeof(bufRecev)-1);
printf("message fromServer: %s\n",bufRecev);
close(sock);
}
message fromServer:(就打印什么)
(3)
//服务
//client 从 server 下载一个文件并保存到本地。
void test4()
{
char* filename = "/Users/mac/Desktop/Level1_1.tmx";
FILE * fp = fopen(filename, "rb");
if (fp == NULL) {
printf("Cannot open file, press any key to exit!\n");
system("pause");
exit(0);
}
int serverSock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(1234);
bind(serverSock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
listen(serverSock, 20);
int clnaddr;
socklen_t nsize = sizeof(clnaddr);
int clnSock = accept(serverSock, (struct sockaddr*)&clnaddr, &nsize);
//循环发送数据,直到文件结尾
char buffer[BUF_SIZE];
size_t nCount;
//当读取到文件末尾,fread() 会返回 0,结束循环
int i = 0;
while ((nCount = fread(buffer, 1, BUF_SIZE, fp)) > 0) {
write(clnSock, buffer, nCount);
i++;
}
shutdown(clnSock, SHUT_WR); //文件读取完毕,断开输出流,向客户端发送FIN包
read(clnSock, buffer, BUF_SIZE);//阻塞,等待客户端接收完毕
fclose(fp);
close(serverSock);
close(clnSock);
printf("********%d\n",i);
}
客户端:
//client 从 server 下载一个文件并保存到本地。
void test4()
{
char * filename = "/Users/mac/Desktop/Level18_1.tmx";
FILE* fp = fopen(filename, "wb");
if (fp == NULL) {
printf("Cannot open file, press any key to exit!\n");
system("pause");
exit(0);
}
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sockaddr;
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(1234);
if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {
printf("链接失败!\n");
}
//循环接受数据,直到文件传输完毕
char buffer[BUF_SIZE];
size_t nCount;
/*
就是文件传输完毕后让 recv() 返回 0,结束 while 循环。
注意:读取完缓冲区中的数据 recv() 并不会返回 0,而是被阻塞,直到缓冲区中再次有数据。
*/
while ((nCount = read(sock, buffer, BUF_SIZE))>0) {
fwrite(buffer, nCount, 1, fp);
}
printf("File transfer success\n");
fclose(fp);
close(sock);
}
运行结果:把服务器上的Level1_1.tmx,拷贝下来名为Level18_1.tmx
(4)
服务器:
//粘包问题
void test3()
{
int serverSock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(1234);
bind(serverSock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
listen(serverSock, 20);
//接受客户端请求
struct sockaddr_in clnAddr;
socklen_t nSize = sizeof(clnAddr);
int clnSock = accept(serverSock, (struct sockaddr*)&clnAddr, &nSize);
char buffer[40];
sleep(5);//让程序暂停5秒
ssize_t strlen = read(clnSock, buffer, sizeof(buffer)-1);//接受客户端发来的数据
write(clnSock, buffer, strlen);
}
客户端
//粘包问题
void test3()
{
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sockaddr;
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockaddr.sin_port = htons(1234);
connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
//获取用户输入的字符串并发送给服务器
char bufSend[40];
for (int i = 0; i < 3; i++) {
printf("input a string: ");
scanf("%s",bufSend);
write(sock, bufSend, strlen(bufSend));
}
//接受服务器传回的数据
char bufRecev[50];
read(sock, bufRecev, sizeof(bufRecev)-1);
printf("\nmessage from server:%s\n",bufRecev);
close(sock);
}
运行结果:input a string: 2(手动输入什么)
input a string: 3
input a string: 4
nmessage from server:234
client 的 send() 发送了三个数据包,而 server 的 recv() 却只接收到一个数据包,这很好的说明了数据的粘包问题。
(5)
通过域名获取IP地址
服务端:
//DNS
void test5()
{
struct hostent *host = gethostbyname("www.baidu.com");
if (!host) {
puts("Get IP address error!");
system("pause");
exit(0);
}
//别名
for (int i = 0; host->h_aliases[i]; i++) {
printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);
}
//地址类型
printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6");
//IP地址
for(int i=0; host->h_addr_list[i]; i++){
printf("IP addr %d: %s\n", i+1, inet_ntoa( *(struct in_addr*)host->h_addr_list[i] ) );
}
}
运行结果:
Aliases 1: www.baidu.cn
Address type: AF_INET
IP addr 1: 111.13.100.92
IP addr 2: 111.13.100.91
(6)
TCP 是面向连接的传输协议,建立连接时要经过三次握手,断开连接时要经过四次握手,中间传输数据时也要回复ACK包确认,多种机制保证了数据能够正确到达,不会丢失或出错。
UDP 是非连接的传输协议,没有建立连接和断开连接的过程,它只是简单地把数据丢到网络中,也不需要ACK包确认。
UDP 传输数据就好像我们邮寄包裹,邮寄前需要填好寄件人和收件人地址,之后送到快递公司即可,但包裹是否正确送达、是否损坏我们无法得知,也无法保证。UDP 协议也是如此,它只管把数据包发送到网络,然后就不管了,如果数据丢失或损坏,发送端是无法知道的,当然也不会重发
服务器
void UDPtest(){
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in seraddr;
memset(&seraddr, 0, sizeof(seraddr));
seraddr.sin_family = AF_INET;
// seraddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址
seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
seraddr.sin_port = htons(1234);
bind(sock, (struct sockaddr*)&seraddr, sizeof(seraddr));
//接受客户端请求
struct sockaddr_in clnaddr;
socklen_t nsize = sizeof(clnaddr);
/*
由于UDP数据的发送端不定,所以 recvfrom() 函数定义为可接收发送端信息的形式,具体参数如下:
sock:用于接收UDP数据的套接字;
buf:保存接收数据的缓冲区地址;
nbytes:可接收的最大字节数(不能超过buf缓冲区的大小);
flags:可选项参数,若没有可传递0;
from:存有发送端地址信息的sockaddr结构体变量的地址;
addrlen:保存参数 from 的结构体变量长度的变量地址值。
*/
/*
Linux和Windows下的 sendto() 函数类似,下面是详细参数说明:
sock:用于传输UDP数据的套接字;
buf:保存待传输数据的缓冲区地址;
nbytes:带传输数据的长度(以字节计);
flags:可选项参数,若没有可传递0;
to:存有目标地址信息的 sockaddr 结构体变量的地址;
addrlen:传递给参数 to 的地址值结构体变量的长度
*/
while (1) {
char buffer[BUF_SIZE];
ssize_t strlen = recvfrom(sock, buffer, BUF_SIZE, 0, (struct sockaddr*)&clnaddr, &nsize);
printf("Message form client: %s\n", buffer);
sendto(sock, buffer, strlen, 0, (struct sockaddr*) &clnaddr, nsize);
}
close(sock);
}
客户端
void UDPtest(){
int sock = socket(AF_INET, SOCK_DGRAM , 0);
//服务器地址信息
struct sockaddr_in sockadr;
sockadr.sin_family = AF_INET;
sockadr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockadr.sin_port = htons(1234);
//不断获取用户输入并发送给服务器,然后接受服务器数据
struct sockaddr* fromAddr;
socklen_t addrLen = sizeof(fromAddr);
int i=1;
while (i) {
char buffer[BUF_SIZE] = {0};
printf("input a string :");
scanf("%s",buffer);
sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&sockadr, sizeof(sockadr));
ssize_t strlen = recvfrom(sock, buffer, BUFSIZ, 0, (struct sockaddr*)&fromAddr, &addrLen);
buffer[strlen] = 0;
printf("Message form server: %s\n", buffer);
}
close(sock);
}
运行结果:
input a string :1
Message form server: 1
input a string :2
Message form server: 2
input a string :3
Message form server: 3