经过几天高强度的学习,对套接字的编程有了初步的认识,今天对这几天所学的知识总结一下;首先简单阐述一下tcp通信;

  TCP提供的是可靠的,顺序的,以及不会重复的数据传输,处理流控制,由于TCP是可靠的,连接的,顺序的,所以TCP一般用于都应用于对传输的完整性,正确性要求严的场合;编写基于tcp的服务器-客户端模型的程序简单流程如下:

  服务器端:

  (1)调用socket()创建一个套接口

  (2)调用bind()函数是服务器进程与一个端口绑定

  (3)调用listen()设置客户接入队列的大小

  (4)调用accept()接受一个连接,如果介入的队列不为空,则返回一个已连接的套接口描述符,

  (5)调用sned()和recv()函数用来在已连接的套接口间进行发送和接收数据

  客户端:

  (1)调用socket()创建套接字

  (2)调用connect()函数向服务器发送连接请求;

  (3)调用send()函数和recv()函数

  下面是服务器端的代码;

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h> //server
int main()
{
int fd = ;
int nfd = ;
int ret = ;
unsigned char data[] = {}; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < ) {
perror("socket");
return ;
}
/*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = htonl(0xc0a8010a);//192.168.1.10
struct sockaddr_in clt;
int len = ; /*绑定*/
ret = bind(fd, (struct sockaddr *)&ser, );
if(ret < ) {
perror("bind");
return ;
} /*监听*/
ret = listen(fd, );
if(ret == -) {
perror("listen");
return ;
} /*接收连接,并且返回一个新的套接字描述符nfd*/
nfd = accept(fd, (struct sockaddr *)&clt, &len);
if(ret < ) {
perror("accept");
return ;
} /*接收*/
ret = recv(nfd, data, , );
if(ret < ) {
perror("recv");
return ;
}
printf("clt said: %s\n", data);
close(fd); return ;
}

服务器端

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h> //client
int main()
{
int sock_fd = ;
int ret = ;
unsigned char *buf = "hello, hao ara you"; /*创建一个套接口*/
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock_fd < ) {
perror("socket");
return ;
} /*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr("192.168.1.10"); //建立链接
ret = connect(sock_fd, (struct sockaddr *)&ser, );
if(ret < ) {
perror("connect");
return ;
} /*发送*/
ret = send(sock_fd, buf, strlen(buf), );
if(ret < ) {
perror("send");
return ;
} close(sock_fd);
return ;
}

客户端

上面程序是基于tcp的简单通信,下面我们利用tcp实现一个服务器多个客户机;要实现一对多,就要使用线程编程,服务器端在不断监听中,如果有连接请求的话,就用通过 accept函数接受并创建一个线程来处理。线程的创建函数为int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);

  下面是这个程序的源码

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h> #define PORT 9527 void *function(void *d);//线程要执行的函数 int main()
{
/*创建套接口*/
pthread_t pid= ;
int nfd = ;
int fd = ;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < ) {
perror("sock");
return ;
}
/*服务器信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(PORT);
ser.sin_addr.s_addr = inet_addr("192.168.1.10");
struct sockaddr_in clt;
int len = ; /*绑定*/
int ret = bind(fd, (struct sockaddr *)&ser, );
if(ret == -) {
perror("bind");
return ;
} /*监听*/
ret = listen(fd, );
if(ret < ) {
perror("listen");
return ;
} while() {
/*接受链接*/
nfd = accept(fd, (struct sockaddr *)&clt, &len);
if(nfd < ) {
perror("accept");
return ;
} /*创建一个线程*/
ret = pthread_create(&pid, NULL, function, (void *)nfd);
if(ret != ) {
perror("pthread_create");
return ;
} pthread_join(pid, NULL); close(nfd);
} close(fd);
return ;
} void *function(void *d)
{
unsigned char buf[] = {};
int nfd = (int )d;
int ret = ; memset(buf, , );
ret = recv(nfd, buf, , );
if(ret < ) {
perror("recv");
return NULL;
}
printf("client said: %s\n", buf); ret = send(nfd, "recv ok", , );
if(ret < ) {
perror("send");
return NULL;
} }

server

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h> #define PORT 9527 int main(int argc, char **argv)
{
if(argc != ) {
printf("using %s <ip address> <message>\n", argv[]);
return ;
}
/*创建套接口*/
int fd = ;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < ) {
perror("socket");
return ;
} /*服务器信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(PORT);
ser.sin_addr.s_addr = inet_addr(argv[]); /*创建链接*/
int ret = connect(fd, (struct sockaddr *)&ser, );
if(ret < ) {
perror("connect");
return ;
} /*访问*/
ret = send(fd, argv[], strlen(argv[]), );
if(ret < ) {
perror("send");
return ;
} char buf[] = {};
ret = recv(fd, buf, , );
if(ret < ) {
perror("recv");
return ;
}
printf("server: %s\n", buf);
close(fd); return ;
}

client

  上面代码需要注意的是,监听程序最大允许接受10个连接请求,如果这十个一直连接不断开的话,后续的连接请求就无法得到处理,所以我们需要在每次请求完毕之后就关闭nfd;下次请求再重新连接;

  第三个程序我们实现基于tcp的聊天程序:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h> int main()
{
/*创建套接口*/
int fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(fd < ){
perror("socket");
exit(EXIT_FAILURE);
} /*服务端信息*/
struct sockaddr_in srv;
srv.sin_family = AF_INET;
srv.sin_port=htons();
srv.sin_addr.s_addr = htonl(INADDR_ANY); /*绑定*/
int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
ret = listen(fd,);
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
struct sockaddr_in snd;
int snd_len = ; /*接受*/
int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
if(nfd < ){
perror("accpet");
exit(EXIT_FAILURE);
} char data[] = {};
char revdata[] = {};
/*聊天*/
while(){
memset(revdata, , );
memset(data, , );
ret = recv(nfd,revdata,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
} printf("client say: %s\n",revdata);
if(strcmp(revdata, "end") == ) {
break;
} ret = read(,data,);
if(ret < ){
perror("read");
exit(EXIT_FAILURE);
}
ret = send(nfd,data,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
} }
close(nfd);
close(fd);
return ;
}

server

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h> int main()
{
/*创建套接口*/
int sock_fd = ;
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock_fd < ) {
perror("socket");
return ;
}
/*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr("192.168.1.10"); /*建立链接*/
int ret = connect(sock_fd, (struct sockaddr *)&ser, );
if(ret == -) {
perror("connect");
return ;
} /*聊天*/
unsigned char data[] = {};
unsigned char rec[] = {};
while() {
memset(data, , );
memset(rec, , );
int r_size = read(, data, );
if(r_size < ) {
perror("read");
return ;
} ret = send(sock_fd, data, strlen(data), );
if(ret < ) {
perror("send");
return ;
} ret = recv(sock_fd, rec, , );
if(ret < ) {
perror("recv");
return ;
}
printf("server said: %s\n", rec);
}
close(sock_fd);
return ;
}

client

上面这个代码存在的缺陷是,发送方跟接收只能发送一句接收一句,不能一次性发送多句,要解决这个问题就要需用到IO多路服用,可以通过这个函数来实现:
  int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

下面贴出代码:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h> int main()
{
/*创建套接口*/
int fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(fd < ){
perror("socket");
exit(EXIT_FAILURE);
} /*服务端信息*/
struct sockaddr_in srv;
srv.sin_family = AF_INET;
srv.sin_port=htons();
srv.sin_addr.s_addr = htonl(INADDR_ANY); /*绑定*/
int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
ret = listen(fd,);
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
struct sockaddr_in snd;
int snd_len = ; /*接受*/
int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
if(nfd < ){
perror("accpet");
exit(EXIT_FAILURE);
} fd_set rfds;
char data[] = {};
char revdata[] = {};
/*聊天*/
while(){ FD_ZERO(&rfds);
FD_SET(,&rfds);
FD_SET(nfd,&rfds);
ret = select(nfd+,&rfds,NULL,NULL,NULL);
if(FD_ISSET(nfd, &rfds)){
ret = recv(nfd,revdata,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
} printf("client say: %s\n",revdata);
if(strcmp(revdata, "end") == ) {
break;
}
}
if(FD_ISSET(, &rfds)) {
ret = read(,data,);
if(ret < ){
perror("read");
exit(EXIT_FAILURE);
}
ret = send(nfd,data,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
}
}
memset(revdata, , );
memset(data, , );
}
close(nfd);
close(fd);
return ;
}

server

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h> int main()
{
/*创建套接口*/
int sock_fd = ;
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock_fd < ) {
perror("socket");
return ;
}
/*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr("192.168.1.10"); /*建立链接*/
int ret = connect(sock_fd, (struct sockaddr *)&ser, );
if(ret == -) {
perror("connect");
return ;
} /*聊天*/
fd_set rfds;
unsigned char data[] = {};
unsigned char rec[] = {};
while() {
memset(data, , );
memset(rec, , );
FD_ZERO(&rfds); //清空
FD_SET(,&rfds);//(标准输入)
FD_SET(sock_fd,&rfds);//添加监听描述符(套接字)
/*多路复用IO*/
ret = select(sock_fd+,&rfds,NULL,NULL,NULL); if(FD_ISSET(, &rfds)){//监听键盘是否有输入,执行接收
int r_size = read(, data, );
if(r_size < ) {
perror("read");
return ;
}
ret = send(sock_fd, data, strlen(data), );
if(ret < ) {
perror("send");
return ;
}
} if(FD_ISSET(sock_fd, &rfds)) {//监听sock_fd是否有输入,执行接收
ret = recv(sock_fd, rec, , );
if(ret < ) {
perror("recv");
return ;
}
printf("server said: %s\n", rec);
}
}
close(sock_fd);
return ;
}

client

    

  

网络编程之套接字(tcp)的更多相关文章

  1. TCP/IP网络编程之套接字类型与协议设置

    套接字与协议 如果相隔很远的两人要进行通话,必须先决定对话方式.如果一方使用电话,另一方也必须使用电话,而不是书信.可以说,电话就是两人对话的协议.协议是对话中使用的通信规则,扩展到计算机领域可整理为 ...

  2. 【TCP/IP网络编程】:01理解网络编程和套接字

    1.网络编程和套接字 网络编程与C语言中的printf函数和scanf函数以及文件的输入输出类似,本质上也是一种基于I/O的编程方法.之所以这么说,是因为网络编程大多是基于套接字(socket,网络数 ...

  3. TCP/IP网络编程之网络编程和套接字

    网络编程和套接字 网络编程又称为套接字编程,就是编写一段程序,使得两台连网的计算机彼此之间可以交换数据.那么,这两台计算机用什么传输数据呢?首先,需要物理连接,将一台台独立的计算机通过物理线路连接在一 ...

  4. UNIX网络编程——原始套接字(dos攻击)

    原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...

  5. UNIX网络编程——原始套接字的魔力【续】

    如何从链路层直接发送数据帧 上一篇里面提到的是从链路层"收发"数据,该篇是从链路层发送数据帧. 上一节我们主要研究了如何从链路层直接接收数据帧,可以通过bind函数来将原始套接字绑 ...

  6. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  7. 19 网络编程--Socket 套接字方法

    1.Socket(也称套接字)介绍 socket这个东东干的事情,就是帮你把tcp/ip协议层的各种数据封装啦.数据发送.接收等通过代码已经给你封装好了 ,你只需要调用几行代码,就可以给别的机器发消息 ...

  8. 网络编程--Socket(套接字)

    网络编程 网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中 有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后 如何可靠高效的进行数据传输.在 ...

  9. 网络编程之套接字socket

    目录 socket套接字 引子 为何学习socket一定要先学习互联网协议 socket是什么 套接字类型 基于文件类型的套接字家族 基于网络类型的套接字家族 套接字工作流程 基于TCP的套接字 简单 ...

  10. 8.7 day28 网络编程 socket套接字 半连接池 通信循环 粘包问题 struct模块

    前置知识:不同计算机程序之间的数据传输 应用程序中的数据都是从程序所在计算机内存中读取的. 内存中的数据是从硬盘读取或者网络传输过来的 不同计算机程序数据传输需要经过七层协议物理连接介质才能到达目标程 ...

随机推荐

  1. Android 添加library的时候出错添加不上

    在向android工程中导入library的时候,会和出现导入不成功,打开查看添加library界面,会发现你添加的library的路径出现D:/work/...?类似的情况,但是别的工程使用的时候又 ...

  2. Android4.0Sd卡移植之使用vold自动挂载sd卡

    在cap631平台上移植android4.0,发现内核驱动没有任何问题,能够读写,当总不能挂载. 后来发现是因为自动挂载需要vold的支持.vold程序负责检查内核的 sysfs 文件系统,发现有SD ...

  3. ubuntu安装qq教程

    安装策略是wine+wine QQ TM2013,wine QQ TM2013是一款专门为wine进行优化的版本 我的ubuntu系统是14.04版本,64位 1. sudo apt-get inst ...

  4. leetcode之旅(9)-Reverse Linked List

    题目描述: Reverse a singly linked list. click to show more hints. Hint: A linked list can be reversed ei ...

  5. Ajax 模糊查询的简单实现

    类似于百度的搜索引擎模糊查询功能,不过百度的模糊查询功能更强大,这里简单实现下. 要实现模糊查询,首先要做的就是把SQL写好.话不多少,直接贴代码了! JSP页面: <%@ page langu ...

  6. C#在PDF中如何以不同颜色高亮文本

    高亮的文本有助于阅读者快速有效地获取文章关键信息.在PDF文件中,对文章的不同文本,关键词.句等进行不同颜色的文本高亮操作,可以使阅读者在阅读过程中有效地区分不同高亮颜色文本的意义.在下面的示例中,我 ...

  7. c#实例化继承类,必须对被继承类的程序集做引用

    0x00 问题 类型“Model.NewModel”在未被引用的程序集中定义.必须添加对程序集“Model, Version=1.0.0.0, Culture=neutral, PublicKeyTo ...

  8. java中内存的使用

    一个java运行起来执行代码,主要的内存消耗有这几块: 1.堆 2.栈 :栈是每个线程一个的,是以消耗的内存是内存大小*线程数,当线程数特多时候需要小心 . 3.直接内存:主要是通道时候的缓存,在内存 ...

  9. jvm性能优化及内存分区

     jvm性能优化及内存分区 2012-09-17 15:51:37 分类: Java Some of the default values for Sun JVMs are listed below. ...

  10. 刚收到一个吃瓜群众看了肯定不信的offer!

    我教过了很多学生了,有的毕业后跟我依然保持联系,有的不知所踪,有的越混越好,有的没有什么变化,这让我不断思考,到底拉开人与人之间差距的是什么呢?