linux网络编程笔记——TCP
1、TCP和UDP
TCP是长连接像持续的打电话,UDP是短消息更像是发短信。TCP需要消耗相对较多的资源,但是传输质量有保障,UDP本身是不会考虑传输质量的问题。
2、网络传输内容
我习惯的做法是直接通过TCP传送结构体,当然前提是收发两端都在程序里对目标结构体有充分的定义。特别说明的一点是,要小心收发两端处理器的大小端问题!而且传输信息头里必须包含长度信息,而且通用的是大端。但是,这里的长度和结构体,我选择用小端进行传输。
3、TCPserver实现
参考了别人多线程的回调写法,看起来不错。
tcputil.c(照搬别人的,文件内有作者信息)
/**************************************************
*
* $description: collection of functions
* $author: smstong
* $date: Tue Apr 16 10:24:22 CST 2013
*
* ************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
/**************************************************
* func: receive n bytes from socket except an error
* params: fd - socket handle
* buf - memory space to write
* n - size of buf
* return: -1 - error;
* >=0 - actually retceived bytes
*************************************************/
ssize_t recvn(int fd, void* buf, size_t n)
{
char* ptr = (char*)buf; // position pointer
size_t left = n; // bytes left to read
while(left > ) {
size_t nread = read(fd, ptr, left);
if(nread<) {
if(errno==EINTR) { // an error occured
nread = ;
} else {
return -;
}
} else if(nread==) { //normally disconnect, FIN segment received
break;
} else {
left -= nread;
ptr += nread;
}
}
return (n-left);
} /********************************************************
* function: write n bytes to socket except error
* params: fd - socket hanle
* buf - src memory
* n - bytes to write
* return: -1 - error
* >=0 - bytes actually written
* ******************************************************/
ssize_t writen(int fd, void* buf, size_t n)
{
char* ptr = (char*)buf;
size_t left = n;
while(left > ) {
size_t nwrite = write(fd, ptr,left);
if(nwrite<) {
if(errno==EINTR) {
nwrite = ;
} else {
return -;
}
} else if(nwrite==) {
break;
} else {
left -= nwrite;
ptr += nwrite;
}
}
return (n-left);
} static void * thread_f(void *); //thread function
typedef int (*message_handler)(int, void *, uint32_t); // callback function called after received one message /*************************************************************
*
* one thread per connection frameset
*
* ***********************************************************/ // thread function's args
struct thread_arg {
int socket;
message_handler msg_handler;
}; int start(uint32_t listenip, uint16_t listenport, message_handler handler)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[];
int n; if( (listenfd = socket(AF_INET, SOCK_STREAM, )) == - ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit();
} memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(listenip);
servaddr.sin_port = htons(listenport); if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
return -;
} if( listen(listenfd, ) == -){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
return -;
} printf("======waiting for client's request======\n");
while(){
if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
/* create a new thread to handle this connection */
pthread_t tid = ;
int rc = ;
struct thread_arg *parg = malloc(sizeof(struct thread_arg));
if(NULL==parg) {
printf("error malloc: %s\n", strerror(errno));
return -;
}
parg->socket = connfd;
parg->msg_handler = handler;
if( != (rc=pthread_create(&tid, NULL, thread_f, parg))) {
printf("%s: %s\n", __func__, strerror(rc));
}
printf(" create thread %u to handle connection %d \n", tid, connfd);
}
close(listenfd);
return ;
}
/***************************
* fun: receive one message
* params: connfd - socket handle
* return: 0 - success;
* -1 - error
*
* **************************/
static int recv_one_message(int connfd, message_handler post_recv_one)
{
uint32_t msg_len = ; /* message length */ /* recv length */
if( != recvn(connfd, &msg_len, )) { // something wrong
return -;
} /*很重要的函数,内存*/
//msg_len = ntohl(msg_len); /* recv body */
if(msg_len > 0x7FFFFFFF) {
printf("message body to large%d\n",msg_len);
return -;
} char* buf = malloc(msg_len);/* allocate memory for message body*/
if(NULL == buf) {
printf("%s: malloc failed!\n", __func__);
return -;
} if(msg_len != recvn(connfd, buf, msg_len)) {
free(buf);
return -;
} if(!=post_recv_one(connfd, buf, msg_len)) { // callback
free(buf);
return -;
} free(buf);
return ;
}
/* thread to handle a connection */
static void * thread_f(void * arg)
{
printf(" enter thread %u\n", pthread_self());
struct thread_arg targ = *((struct thread_arg*)arg);
int connfd = targ.socket;
message_handler post_recv_one = targ.msg_handler;
free(arg); int i = ;
while() {
if( != recv_one_message(connfd, post_recv_one)) {
break;
}
printf("%d message : %d\n",connfd,i++);
}
close(connfd);
printf(" leave thread %u\n", pthread_self());
}
tcputil.h
#ifndef TCPUTIL_H
#define TCPUTIL_H #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //结构体在内存里紧凑排列
#pragma pack(1)
typedef struct { /* raw data */
double tow; // GPS time of the week in second
unsigned char numGps;
unsigned char numBds;
unsigned char numGln;
unsigned char system[MAXSAT]; // system, 0, 1, 2 GPS, BDS & GLN
unsigned char PRN[MAXSAT]; // PRN number
double dDO[MAXSAT]; // Doppler in Hz
double dPR[MAXSAT]; // pseudorange in meter
} diff_t;
#pragma pack() ssize_t writen(int fd, void* buf, size_t n);
ssize_t recvn(int fd, void* buf, size_t n); /*callback function called after received one message, 0-success, -1-error*/
typedef int (*message_handler)(int socket, void * buf, uint32_t size); int start(uint32_t listenip, uint16_t listenport, message_handler handler); #endif
server.c
#include "tcputil.h" diff_t *diff; /* callback called after one message received. */
int msg_handler(int fd, void* buf, uint32_t n)
{
if (!strncmp(buf,"\nrover\n",strlen("\nrover\n")))
{
writen(fd, (char *)diff, sizeof(diff_t));
printf("\t\tsend\n\n");
}
if (!strncmp(buf,"\nstation\n",strlen("\nstation\n")))
{
memcpy((char *)diff, buf+strlen("\nstation\n"), sizeof(diff_t));
printf("\t\tupdate\n\n");
} return ;
} int main(int argc, char** argv)
{
diff=malloc(sizeof(diff_t));
bzero(diff,sizeof(diff_t));
start(,PORT, msg_handler);
free(diff);
}
4、TCPclient实现
略粗糙,将就着看吧
rover.c
#include "tcputil.h" int main(int argc, const char *argv[])
{
diff_t *diff=malloc(sizeof(diff_t));
bzero(diff,sizeof(diff_t)); struct sockaddr_in addr;
int sock; if(argc != )
{
fprintf(stderr,"need an IP address\n");
return ;
}
memset(&addr, , sizeof(addr));
addr.sin_family = AF_INET;
inet_aton(argv[],&addr.sin_addr);
addr.sin_port = htons(PORT);
if( (sock = socket(PF_INET, SOCK_STREAM,)) < )
{
perror("socket");
}
if( connect(sock, (struct sockaddr *)&addr, sizeof(addr)) )
{
perror("connect");
}
printf("Connected!\n");
printf("I am rover!\n");
printf("Connected to %s:%d\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)); char tag[]="\nrover\n"; uint32_t len = strlen(tag), msg_len=+strlen(tag); char *msg=malloc(msg_len);
bzero(msg,msg_len); memcpy(msg,&len,);
memcpy(msg+,tag,len); while(){
sleep();
if(write(sock,msg,msg_len) != msg_len)
{
perror("write");
}
read(sock,(char *)diff,sizeof(diff_t));
} free(msg);
close(sock);
return ;
}
station.c
#include "tcputil.h" int main(int argc, const char *argv[])
{
struct sockaddr_in addr;
int sock; diff_t *diff=malloc(sizeof(diff_t));
bzero(diff,sizeof(diff_t)); if(argc != )
{
fprintf(stderr,"need an IP address\n");
return ;
}
memset(&addr, , sizeof(addr));
addr.sin_family = AF_INET;
inet_aton(argv[],&addr.sin_addr);
addr.sin_port = htons(PORT);
if( (sock = socket(PF_INET, SOCK_STREAM,)) < )
{
perror("socket");
}
if( connect(sock, (struct sockaddr *)&addr, sizeof(addr)) )
{
perror("connect");
}
printf("Connected!\n");
printf("I am station!\n");
printf("Connected to %s:%d\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)); char tag[]="\nstation\n"; uint32_t len = strlen(tag)+sizeof(diff_t);
int msg_len = +strlen(tag)+sizeof(diff_t);
char *msg=malloc(msg_len);
bzero(msg,msg_len); memcpy(msg,&len,);
memcpy(msg+,tag,strlen(tag)); while(){
memcpy(msg++strlen(tag),diff,sizeof(diff_t));
printf("!!!!!!!!!!!!%d\n", msg_len);
if(write(sock,msg,msg_len) != msg_len)
{
perror("write");
}
sleep();
}
free(msg);
close(sock);
return ;
}
附上makefile一枚
all: rover server station rover: rover.c tcputil.o
gcc rover.c tcputil.o -o rover -lpthread server: server.c tcputil.o
gcc server.c tcputil.o -o server -lpthread station:station.c tcputil.o
gcc station.c tcputil.o -o station -lpthread tcputil:tcputil.c
gcc tcputil.c -c -lpthread .PHONY: clean clean:
rm -f *.o rover server station
linux网络编程笔记——TCP的更多相关文章
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- Linux网络编程笔记(修订版)
我的网络编程笔记, 因为最近又要做Linux下的网络编程,故重新修订, 其中一些内容参考了文末的链接及文章 1. 基本概念 2. 基本接口 2.1. 打开一个socket 2.2. 将 ...
- 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...
- Linux网络编程系列-TCP传输控制
滑动窗口(sliding window) 滑动窗口是用于流量控制的,发送端根据接收端的处理能力发送数据,不至于造成过多的丢包. 是发送方和接收方间的协调,对方的接收窗口大小就是自己的发送窗口大小. 在 ...
- linux网络编程系列-TCP/IP模型
### OSI:open system interconnection ### 开放系统互联网模型是由ISO国际标准化组织定义的网络分层模型,共七层 1. 物理层:物理定义了所有电子及物理设备的规范, ...
- 【Linux 网络编程】TCP/IP四层模型
应用层.传输层.网络层.链路层 链路层:常用协议 ARP(将物理地址转化为IP地址) RARP(将IP地址转换为物理地址) 网络层(IP层):重要协议ICMP IP IGMP 传输层:重要的协议TCP ...
- Linux 网络编程(TCP)
客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...
- Linux网络编程系列-TCP编程实例
实例: client #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #inc ...
- linux网络编程笔记——UDP
目前这部分代码会出现阻塞问题,暂时尚未解决 #include "udp.h" #include <stdio.h> #include <string.h> ...
随机推荐
- Django admin site(二)ModelAdmin methods
ModelAdmin methods save_model(request, obj, form, change) 此方法为admin界面用户保存model实例时的行为.request为HttpReq ...
- mysql shell
mysql 查询10分钟以内的数据:select *from t_agent where int_last_login>=CURRENT_TIMESTAMP - INTERVAL 10 MINU ...
- ios越狱开发第一次尝试记录
1.THEOS的makefile文件中的THEOS_DEVICE_IP要写在第一行 2.如果make package install报错 dpkg status database is locked ...
- tlProPlayer for windows
tlProPlayer tlProPlayer简介 tlProPlayer是一款定位高性能产品,支持透传,原生输出,并支持硬解码(硬件加速)的多媒体产品,兼容tlplayer所有特性.支持视频加密播放 ...
- const和readonly的区别
http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html http://www.codeproject.com/Tips/803 ...
- tuxedo入门
为文件增加用户执行权限: 官网下载tuxedo111120_64_Linux_01_x86.bin su //进入root操作,防止权限不够 创建文件夹,用来做tuxedo文件的安装路径 cd /op ...
- CocoaPods requires your terminal to be using UTF-8 encoding
WARNING: CocoaPods requires your terminal to be using UTF-8 encoding. See https://github.com/CocoaPo ...
- drop.delete.trauncat的区别
delete删除数据,保留表结构,可以回滚,如果数据量大,很慢,回滚是因为备份了删除的数据(删除数据时有两个动作,删除和备份) truncate删除所有数据,保留表结构,不可以回滚,一次全部删除所有数 ...
- 给你的JAVA程序配置参数(Properties的使用)
我们在写JAVA程序时,很多时候运行程序的参数是需要动态改变的 测试时一系列参数,运行时一系列参数 又或者数据库地址也需要配一套参数,以方便今后的动态部署 这些变量的初始化,我们在写小DEMO时完全可 ...
- bzoj1063
仔细观察可以发现,这个规划路径很像树链剖分 树链剖分的经典定理:任意一个点到根的所经过轻边不超过logn 而这个规划路径所走公路相当于轻边,也就是说,不便利度不会很大 那么直接dp即可,设f[x,i, ...