自测之Lesson15:TCP&UDP网络编程
题目:编写一个TCP通信的程序。
实现代码:
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define PORT 0xaaaa // 服务端
void startServe()
{
int iRet; // socket()
int fd; // 文件描述符
fd = socket(PF_INET, SOCK_STREAM, 0); // 创建文件描述符,并确定是用TCP还是UDP等
if (fd < 0) {
perror("fail socket");
return;
} // bind()
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 即使目标地址不是我,只要发到该计算机上,我就能接收 iRet = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); // 将文件描述符与本机地址绑定
if (iRet < 0) {
perror("fail bind");
close(fd); // 释放资源
return;
} // listen()
iRet = listen(fd, 5); // 最多监听5个连接请求
if (iRet < 0) {
perror("fail listen");
close(fd);
return;
}
printf("Server start OK, wait connect...\n"); // accept()
char szBuf[1024];
char szMsg[] = "Welcome...";
struct sockaddr_in clientAddr; // 客户端地址
socklen_t addrlen = sizeof(clientAddr);
while(1) {
int newFd; // 此newFd用于与客户端通信
newFd = accept(fd, (struct sockaddr*)&clientAddr, &addrlen);
if (newFd < 0) {
perror("fail accept");
break;
} char *pClientAddr = inet_ntoa(clientAddr.sin_addr); // 整数IP转字符串IP
int clientPort = ntohs(clientAddr.sin_port); // 网络字节序转主机字节序
printf("Connect from %s:%d\n", pClientAddr, clientPort);
memset(szBuf, 0, 1024);
iRet = read(newFd, szBuf, 1024);
if (iRet < 0) {
perror("fail read");
break;
}
printf("Recv:%s\n", szBuf);
write(newFd, szMsg, strlen(szMsg));
close(newFd); // 关闭当前accept创建的文件描述符
}
close(fd);
return;
} // 客户端
void startClient()
{
int iRet; // socket()
int fd;
fd = socket(PF_INET, SOCK_STREAM, 0);
if(fd < 0) {
perror("fail socket");
return;
} // connect()
struct sockaddr_in srvAddr;
srvAddr.sin_family = AF_INET;
srvAddr.sin_addr.s_addr = inet_addr("192.168.85.128"); // 服务端的ip地址
srvAddr.sin_port = htons(PORT); // 服务端的端口号
iRet = connect(fd, (struct sockaddr*)&srvAddr, sizeof(srvAddr));
if (iRet != 0) {
perror("fail connect");
return;
}
printf("Connect success\n");
fprintf(stderr, "Send:"); // read() & write()
char szBuf[1024];
memset(szBuf, 0, 1024);
read(STDIN_FILENO, szBuf, 1024); // 从标准输入 输入消息
write(fd, szBuf, strlen(szBuf));
char szRcv[1024]; memset(szRcv, 0, 1024);
read(fd, szRcv, 1024);
printf("[CLIENT]Rcv:%s\n", szRcv); close(fd);
return;
} int main(int argc, char **argv)
{
if (argc != 2 ||
(strcmp(argv[1], "s") && strcmp(argv[1], "c"))) {
printf("Usage: %s [ s | c ]\n", argv[0]);
printf("\ts: start server\n");
printf("\tc: start client\n");
return 0;
}
if (argv[1][0] == 's') {
startServe();
}
else if (argv[1][0] == 'c') {
startClient();
}
return 0;
} /* ReadMe */
/*
* 先启动服务端 --> ./a.out s
* 再启动客户端 --> ./a.out c
*/
题目:编写一个UDP通信的程序。
实现代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h> #define SRV_PORT 0xaaaa // 服务端 端口号
#define CLI_PORT 0xbbbb // 客户端 端口号
#define IP_ADDRESS "10.162.73.120" void startServer()
{
int iRet; // socket()
int fd;
fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("fail socket");
return;
} // bind()
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SRV_PORT);
iRet = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if (iRet != 0) {
perror("fail bind");
return;
} // recvfrom() & sendto()
struct sockaddr_in cliAddr;
socklen_t addrLen = sizeof(cliAddr);
char szRcv[1024];
char szSnd[1024];
while(1) {
// recvfrom()
memset(szRcv, 0, 1024);
iRet = recvfrom(fd, szRcv, 1024, 0, (struct sockaddr*)&cliAddr, &addrLen);
if (iRet < 0) {
perror("fail recvfrom");
close(fd);
break;
}
char *pcliAddr = inet_ntoa(cliAddr.sin_addr);
int cliPort = ntohs(cliAddr.sin_port);
printf("Recv from client[%s:%d]\n", pcliAddr, cliPort);
printf("Recv:%s\n", szRcv); // sendto()
fprintf(stderr, "Send:");
memset(szSnd, 0, 1024);
read(STDIN_FILENO, szSnd, 1024);
iRet = sendto(fd, szSnd, strlen(szSnd), 0, (struct sockaddr*)&cliAddr, addrLen); }
close(fd);
} void startClient()
{
int iRet; // socket()
int fd;
fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("fail socket");
return;
} // bind()
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(CLI_PORT);
iRet = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if (iRet != 0) {
perror("fail bind");
return;
} // recvfrom() & sendto()
struct sockaddr_in srvAddr;
socklen_t addrLen = sizeof(srvAddr);
// 对端的地址信息,用于sendto()函数
srvAddr.sin_family = AF_INET;
srvAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
srvAddr.sin_port = htons(SRV_PORT);
char szRcv[1024];
char szSnd[1024];
while(1) {
// sendto()
fprintf(stderr, "Send:");
memset(szSnd, 0, 1024);
read(STDIN_FILENO, szSnd, 1024);
sendto(fd, szSnd, strlen(szSnd), 0, (struct sockaddr*)&srvAddr, addrLen); // read()
memset(szRcv, 0, 1024);
read(fd, szRcv, 1024); // 上面的sendto()已经获得对端地址,此处可简写
printf("Recv:%s\n", szRcv);
}
close(fd);
} int main(int argc, char **argv)
{
if (argc != 2 ||
(strcmp(argv[1], "c") && strcmp(argv[1], "s")))
{
printf("Usage:%s [ s | c ]\n", argv[0]);
printf("\ts: start to server\n");
printf("\tc: start to client\n");
return 0;
}
if (argv[1][0] == 's') {
startServer();
}
else if (argv[1][0] == 'c') {
startClient();
}
return 0;
}
题目:编写一个抓包程序,要求抓取封装TCP报文段的包,并打印出包的头部信息。
实现代码:
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define PORT 0Xaaaa // 此端口仅用于bind(),而该程序可抓发送到任意端口的包 typedef struct _ipHeader {
// unsigned char ucVer:4;
// unsigned char ucHeadLen:4;
unsigned char ucVerHeadLen; // 不应该在此处用位域,可在后面提取位数
unsigned char ucTos;
unsigned short usLen;
unsigned short usIdent;
// unsigned short usFlag:3;
// unsigned short usOffset:13;
unsigned short usFlagOffset;
unsigned char ucTTL;
unsigned char ucProtocol;
unsigned short usChkSum;
// unsigned int uiSrcIp;
// unsigned int uiDestIp;
struct in_addr SrcIp;
struct in_addr DestIp;
char data[0];
} IP_HEADER; typedef struct _tcpHeader {
unsigned short SrcPort;
unsigned short DestPort;
unsigned int Seq;
unsigned int Ack;
// unsigned short HeadLen:4;
// unsigned short Save:6;
// unsigned short URG:1;
// unsigned short ACK:1;
// unsigned short PSH:1;
// unsigned short RST:1;
// unsigned short SYN:1;
// unsigned short FIN:1;
unsigned short HeadLenFlag; // 包括首部长度、保留、URG标志等字段
unsigned short Window;
unsigned short ChkSum;
unsigned short UrgPoint;
char data[0];
} TCP_HEADER; void printIpHeader(char szBuf[])
{
IP_HEADER *pHeader = (IP_HEADER*)szBuf;
printf("\n================IP HEADER================\n");
printf("\tVersion:%d\n", (pHeader->ucVerHeadLen) >> 4);
printf("\tHeadLen:%d\n", (pHeader->ucVerHeadLen) & 0x0f);
printf("\tSOUR IP:%s\n", inet_ntoa(pHeader->SrcIp));
printf("\tDEST IP:%s\n", inet_ntoa(pHeader->DestIp));
printf("=========================================\n");
} void printTcpHeader(char szBuf[])
{
TCP_HEADER *pHeader = (TCP_HEADER*)szBuf;
printf("\n===============TCP HEADER================\n");
printf("\tSOUR PORT:%d\n", ntohs(pHeader->SrcPort));
printf("\tDEST PORT:%d\n", ntohs(pHeader->DestPort));
printf("=========================================\n");
} void startCapturePacket()
{
int iRet; int fd;
fd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP/* = NUM'6' */); // 抓取封装TCP报文段的IP数据报
if (fd < 0) {
perror("fail socket");
return;
} struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY); iRet = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if (iRet < 0) {
perror("fail bind");
close(fd);
return;
} char szBuf[1024];
while(1) {
memset(szBuf, 0, 1024);
read(fd, szBuf, 1024); // 将抓到的包整个存到szBuf中,此处szBuf的大小不是很合适
printIpHeader(szBuf); // 打印IP头部部分信息
printTcpHeader(szBuf); // 打印TCP报文端头部部分信息
}
close(fd);
return;
} int main()
{
startCapturePacket();
return 0;
}
自测之Lesson15:TCP&UDP网络编程的更多相关文章
- TCP/UDP网络编程的基础知识与基本示例(windows和Linux)
一.TCP编程的一般步骤 服务器端: 1.创建一个socket,用函数socket() 2.绑定IP地址.端口等信息到socket上,用函数bind() 3.开启监听,用函数listen() 4.接收 ...
- JAVA UDP网络编程学习笔记
一.UDP网络编程概述 采用TCP协议通信时,客户端的Socket必须先与服务器建立连接,连接建立成功后,服务器端也会持有客户端连接的Socket,客户端的Socket与服务器端的Socket是对应的 ...
- 三十天学不会TCP,UDP/IP编程--MAC地址和数据链路层
这篇文章主要是来做(da)推(guang)介(gao)的!由于这两年接触到了比较多的这方面的知识,不想忘了,我决定把他们记录下来,所以决定在GitBook用半年时间上面写下来,这是目前写的一节,后面会 ...
- 《TCP/IP网络编程》
<TCP/IP网络编程> 基本信息 作者: (韩)尹圣雨 译者: 金国哲 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:9787115358851 上架时间:2014-6- ...
- TCP/IP网络编程系列之四(初级)
TCP/IP网络编程系列之四-基于TCP的服务端/客户端 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于流的 ...
- TCP/IP网络编程系列之三(初级)
TCP/IP网络编程系列之三-地址族与数据序列 分配给套接字的IP地址和端口 IP是Internet Protocol (网络协议)的简写,是为首发网络数据而分配给计算机的值.端口号并非赋予计算机值, ...
- TCP/IP网络编程之多播与广播
多播 多播方式的数据传输是基于UDP完成的,因此,与UDP服务端/客户端的实现非常接近.区别在于,UDP数据传输以单一目标进行,而多播数据同时传递到加入(注册)特定组的大量主机.换言之,采用多播方式时 ...
- TCP/IP网络编程之套接字的多种可选项
套接字可选项进而I/O缓冲大小 我们进行套接字编程时往往只关注数据通信,而忽略了套接字具有的不同特性.但是,理解这些特性并根据实际需要进行更改也十分重要.之前我们写的程序在创建好套接字后都是未经特别操 ...
- TCP/IP网络编程之基于TCP的服务端/客户端(一)
理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于流(stream)的套接字.TCP是Transmissi ...
随机推荐
- JavaScript 中 this 的原理
一.问题 学习 JavaScript 其中一个标志就是理解下面两种写法,会输出有不一样的结果. var obj = { foo: function () {} }; var foo = obj.foo ...
- 发现新大陆QuickBurro中间件 http://www.quickburro.org
可以做手机.网页,三层C/S?这么神?
- Hbase过滤器
Hbase过滤器简介 HBase的基本API,包括增.删.改.查等,增.删都是相对简单的操作,与传统的RDBMS相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根据行键的范围来查 ...
- hive 查看表结构和属性
1.查看数据库/表 show databases/tables; 2.切换数据库 use database_name; 3.查看表结构 desc table_name; 4.查看表详细属性 desc ...
- 电子相册之bitmap
位图文件主要分为3部分:1. 文件信息头 14Byte 2. 位图信息头 40Byte 3. RGB颜色阵列 由图像长宽尺寸决定 1. 文件信息头 定义结构体: typedef s ...
- 『Python基础-10』字典
# 『Python基础-10』字典 目录: 1.字典基本概念 2.字典键(key)的特性 3.字典的创建 4-7.字典的增删改查 8.遍历字典 1. 字典的基本概念 字典一种key - value 的 ...
- 北京Uber优步司机奖励政策(1月7日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- (AOSP)repo checkout指定版本
aosp 怎么切换分支? To properly switch Android version, all you need to change is branch for your manifest ...
- MyBatis-SELECT基本查询
1.返回一个LIST <!-- public List<Employee> getEmpsByLastNameLike(String lastName); --> <!- ...
- 『Python Kivy』API说明:kivy.app.App
App类是创建Kivy应用的基础.我们可以将其看成是Kivy运行循环当中的主入口.在绝大多数的例子中,你创建这个类的子类,然后构建你自己的应用.当你已经准备好开始应用的整个生命周期时,你可以实例化你定 ...